Skip to content

Commit 9570b07

Browse files
committed
POC: sync from dfly to valkey
Signed-off-by: Abhijat Malviya <[email protected]>
1 parent fd5a3c7 commit 9570b07

File tree

5 files changed

+144
-1
lines changed

5 files changed

+144
-1
lines changed

src/server/conn_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ struct ConnectionState {
154154
std::string repl_ip_address;
155155
uint32_t repl_listening_port = 0;
156156
DflyVersion repl_version = DflyVersion::VER1;
157+
bool is_valkey = false;
157158
};
158159

159160
struct SquashingInfo {

src/server/dflycmd.cc

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,119 @@ void DflyCmd::Load(CmdArgList args, RedisReplyBuilder* rb, ConnectionContext* cn
649649
rb->SendOk();
650650
}
651651

652+
namespace {
653+
654+
struct Pipe final : io::Source, io::Sink {
655+
io::Result<unsigned long> ReadSome(const iovec* v, uint32_t len) override {
656+
if (done) {
657+
return 0;
658+
}
659+
660+
ec.await([&] { return rpos < wpos; });
661+
auto bytes_read = 0;
662+
663+
while (rpos < wpos && len > 0) {
664+
const auto chunk_size = min(wpos - rpos, v->iov_len);
665+
std::copy_n(buffer.begin() + rpos, chunk_size, static_cast<char*>(v->iov_base));
666+
bytes_read += chunk_size;
667+
rpos += chunk_size;
668+
++v;
669+
--len;
670+
}
671+
672+
if (rpos == wpos && wpos == cap) {
673+
rpos = 0;
674+
wpos = 0;
675+
ec.notifyAll();
676+
}
677+
678+
return bytes_read;
679+
}
680+
681+
io::Result<unsigned long> WriteSome(const iovec* v, uint32_t len) override {
682+
CHECK(!done);
683+
ec.await([&] { return wpos < cap; });
684+
int bytes_written = 0;
685+
686+
while (wpos < cap && len > 0) {
687+
const auto chunk_size = std::min(cap - wpos, v->iov_len);
688+
auto p = static_cast<const char*>(v->iov_base);
689+
std::copy_n(p, chunk_size, buffer.begin() + wpos);
690+
bytes_written += chunk_size;
691+
wpos += chunk_size;
692+
++v;
693+
--len;
694+
}
695+
696+
std::string debugging{reinterpret_cast<const char*>(buffer.data() + 5), wpos};
697+
VLOG(1) << "debugging: " << debugging;
698+
ec.notifyAll();
699+
return bytes_written;
700+
}
701+
702+
std::array<uint8_t, 1024> buffer;
703+
size_t rpos{0};
704+
size_t wpos{0};
705+
size_t cap{1024};
706+
std::atomic_bool done{false};
707+
fb2::EventCount ec;
708+
};
709+
710+
} // namespace
711+
712+
void DflyCmd::StartValkeySync() {
713+
auto Write = [this](auto v) {
714+
const auto buf = io::Bytes(reinterpret_cast<const unsigned char*>(v.data()), v.size());
715+
CHECK(!_valkey_replica->conn->socket()->Write(buf));
716+
};
717+
718+
CHECK(_valkey_replica.has_value()) << "There is no valkey replica to sync with";
719+
720+
// Since we do not know the size of rdb up front, use the EOF protocol, send
721+
// "$EOF:<40-random-chars>\n" first, then the same 40 chars at the end
722+
std::string eof_mark(40, 'X');
723+
std::string eof_mark_with_prefix = absl::StrCat("$EOF:", eof_mark, "\n");
724+
725+
Write(eof_mark_with_prefix);
726+
727+
for (unsigned i = 0; i < shard_set->size(); ++i) {
728+
Pipe p;
729+
auto cb = [&] {
730+
std::array<uint8_t, 128> backing;
731+
const io::MutableBytes mb{backing};
732+
while (!p.done) {
733+
if (auto n = p.Read(mb); !n.has_value() || n.value() == 0) {
734+
break;
735+
}
736+
CHECK(!_valkey_replica->conn->socket()->Write(mb));
737+
}
738+
739+
if (auto n = p.Read(mb); n.has_value() && n.value()) {
740+
CHECK(!_valkey_replica->conn->socket()->Write(mb));
741+
}
742+
};
743+
auto drain_fb = fb2::Fiber("replica-drain-fb", cb);
744+
745+
shard_set->Await(i, [&p, this, i] {
746+
auto shard = EngineShard::tlocal();
747+
auto mode = i == 0 ? SaveMode::SINGLE_SHARD_WITH_SUMMARY : SaveMode::SINGLE_SHARD;
748+
RdbSaver saver{&p, mode, false, ""};
749+
if (mode == SaveMode::SINGLE_SHARD_WITH_SUMMARY) {
750+
CHECK(!saver.SaveHeader(saver.GetGlobalData(&sf_->service())));
751+
}
752+
753+
saver.StartSnapshotInShard(false, &_valkey_replica->exec_st, shard);
754+
CHECK(!saver.WaitSnapshotInShard(shard));
755+
p.done = true;
756+
VLOG(1) << "finished writing snapshot for shard " << shard->shard_id();
757+
});
758+
759+
drain_fb.JoinIfNeeded();
760+
}
761+
762+
Write(eof_mark);
763+
}
764+
652765
OpStatus DflyCmd::StartFullSyncInThread(FlowInfo* flow, ExecutionState* exec_st,
653766
EngineShard* shard) {
654767
DCHECK(shard);
@@ -730,6 +843,11 @@ void DflyCmd::StartStableSyncInThread(FlowInfo* flow, ExecutionState* exec_st, E
730843
};
731844
}
732845

846+
void DflyCmd::CreateValkeySyncSession(facade::Connection* conn) {
847+
fb2::LockGuard lk(mu_);
848+
_valkey_replica.emplace(conn, [](const GenericError&) {});
849+
}
850+
733851
auto DflyCmd::CreateSyncSession(ConnectionState* state) -> std::pair<uint32_t, unsigned> {
734852
util::fb2::LockGuard lk(mu_);
735853
unsigned sync_id = next_sync_id_++;

src/server/dflycmd.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ class DflyCmd {
129129
util::fb2::SharedMutex shared_mu; // See top of header for locking levels.
130130
};
131131

132+
struct ValkeyReplica {
133+
ValkeyReplica(facade::Connection* conn, ExecutionState::ErrHandler h) : conn{conn}, exec_st{h} {
134+
}
135+
facade::Connection* conn = nullptr;
136+
ExecutionState exec_st;
137+
};
138+
132139
public:
133140
DflyCmd(ServerFamily* server_family);
134141

@@ -142,6 +149,7 @@ class DflyCmd {
142149

143150
// Create new sync session. Returns (session_id, number of flows)
144151
std::pair<uint32_t, unsigned> CreateSyncSession(ConnectionState* state) ABSL_LOCKS_EXCLUDED(mu_);
152+
void CreateValkeySyncSession(facade::Connection* conn);
145153

146154
// Master side access method to replication info of that connection.
147155
std::shared_ptr<ReplicaInfo> GetReplicaInfoFromConnection(ConnectionState* state);
@@ -156,6 +164,7 @@ class DflyCmd {
156164

157165
// Tries to break those flows that stuck on socket write for too long time.
158166
void BreakStalledFlowsInShard() ABSL_NO_THREAD_SAFETY_ANALYSIS;
167+
void StartValkeySync();
159168

160169
private:
161170
using RedisReplyBuilder = facade::RedisReplyBuilder;
@@ -238,6 +247,8 @@ class DflyCmd {
238247
using ReplicaInfoMap = absl::btree_map<uint32_t, std::shared_ptr<ReplicaInfo>>;
239248
ReplicaInfoMap replica_infos_ ABSL_GUARDED_BY(mu_);
240249

250+
std::optional<ValkeyReplica> _valkey_replica = std::nullopt;
251+
241252
mutable util::fb2::Mutex mu_; // Guard global operations. See header top for locking levels.
242253
};
243254

src/server/server_family.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,14 @@ void ServerFamily::ReplTakeOver(CmdArgList args, const CommandContext& cmd_cntx)
37713771
return builder->SendOk();
37723772
}
37733773

3774+
void ServerFamily::PSync(CmdArgList args, const CommandContext& cmd_cntx) {
3775+
auto* rb = static_cast<RedisReplyBuilder*>(cmd_cntx.rb);
3776+
auto response = absl::StrFormat("FULLRESYNC %s %ld", master_replid_, 0);
3777+
rb->SendSimpleString(response);
3778+
3779+
dfly_cmd_->StartValkeySync();
3780+
}
3781+
37743782
void ServerFamily::ReplConf(CmdArgList args, const CommandContext& cmd_cntx) {
37753783
auto* builder = cmd_cntx.rb;
37763784
{
@@ -3856,6 +3864,9 @@ void ServerFamily::ReplConf(CmdArgList args, const CommandContext& cmd_cntx) {
38563864
VLOG(2) << "Received client ACK=" << ack;
38573865
cntx->replication_flow->last_acked_lsn = ack;
38583866
return;
3867+
} else if (cmd == "VERSION" && args.size() == 2) {
3868+
cntx->conn_state.replication_info.is_valkey = true;
3869+
dfly_cmd_->CreateValkeySyncSession(cntx->conn());
38593870
} else {
38603871
VLOG(1) << "Error " << cmd << " " << arg << " " << args.size();
38613872
return err_cb();
@@ -4161,7 +4172,8 @@ void ServerFamily::Register(CommandRegistry* registry) {
41614172
<< CI{"SLOWLOG", CO::ADMIN | CO::FAST, -2, 0, 0, acl::kSlowLog}.HFUNC(SlowLog)
41624173
<< CI{"SCRIPT", CO::NOSCRIPT | CO::NO_KEY_TRANSACTIONAL, -2, 0, 0, acl::kScript}.HFUNC(Script)
41634174
<< CI{"DFLY", CO::ADMIN | CO::GLOBAL_TRANS | CO::HIDDEN, -2, 0, 0, acl::kDfly}.HFUNC(Dfly)
4164-
<< CI{"MODULE", CO::ADMIN, 2, 0, 0, acl::kModule}.HFUNC(Module);
4175+
<< CI{"MODULE", CO::ADMIN, 2, 0, 0, acl::kModule}.HFUNC(Module)
4176+
<< CI{"PSYNC", CO::ADMIN | CO::GLOBAL_TRANS, -2, 0, 0, acl::kDfly}.HFUNC(PSync);
41654177
}
41664178

41674179
} // namespace dfly

src/server/server_family.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ class ServerFamily {
360360
void Script(CmdArgList args, const CommandContext& cmd_cntx);
361361
void SlowLog(CmdArgList args, const CommandContext& cmd_cntx);
362362
void Module(CmdArgList args, const CommandContext& cmd_cntx);
363+
void PSync(CmdArgList args, const CommandContext& cmd_cntx);
363364

364365
void SyncGeneric(std::string_view repl_master_id, uint64_t offs, ConnectionContext* cntx);
365366

0 commit comments

Comments
 (0)