From 19b2cc20df269e31026041c247319aaacf3dd4ff Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Tue, 9 Jul 2024 22:19:56 +0200 Subject: [PATCH] box: make instance_vclock const No code besides box.cc can now update instance's vclock explicitly. That is a protection against hacks like #9916. Closes #10113 NO_DOC=refactoring NO_TEST=refactoring NO_CHANGELOG=refactoring --- src/box/applier.cc | 8 ++++++-- src/box/box.cc | 17 +++++++++++++++-- src/box/box.h | 14 +++++++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/box/applier.cc b/src/box/applier.cc index 299c2b9faa..cd16893804 100644 --- a/src/box/applier.cc +++ b/src/box/applier.cc @@ -788,7 +788,9 @@ applier_wait_snapshot(struct applier *applier) * Used to initialize the replica's initial * vclock in bootstrap_from_master() */ - xrow_decode_vclock_xc(&row, instance_vclock); + struct vclock vclock; + xrow_decode_vclock_xc(&row, &vclock); + box_init_instance_vclock(&vclock); } coio_read_xrow(io, ibuf, &row); @@ -844,7 +846,9 @@ applier_wait_snapshot(struct applier *applier) * vclock yet, do it now. In 1.7+ * this vclock is not used. */ - xrow_decode_vclock_xc(&row, instance_vclock); + struct vclock vclock; + xrow_decode_vclock_xc(&row, &vclock); + box_init_instance_vclock(&vclock); } break; /* end of stream */ } else if (iproto_type_is_error(row.type)) { diff --git a/src/box/box.cc b/src/box/box.cc index 5cabd6b576..2141c50bc5 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -125,7 +125,7 @@ struct rlist box_on_shutdown_trigger_list = struct event *box_on_shutdown_event = NULL; const struct vclock *box_vclock = instance_vclock; -struct vclock *instance_vclock = &instance_vclock_storage; +const struct vclock *instance_vclock = &instance_vclock_storage; const char *box_auth_type; @@ -5107,7 +5107,12 @@ bootstrap_from_master(struct replica *master) return false; } assert(applier->state == APPLIER_READY); - + /* + * In case of rejoin the vclock could be already set to send it in the + * ballot and for other global things. Make it unset again so the + * applier could "init" it again. + */ + vclock_clear(&instance_vclock_storage); say_info("bootstrapping replica from %s at %s", tt_uuid_str(&master->uuid), sio_strfaddr(&applier->addr, applier->addr_len)); @@ -6103,6 +6108,14 @@ box_init(void) sizeof(struct sync_trigger_data)); } +void +box_init_instance_vclock(const struct vclock *vclock) +{ + if (vclock_is_set(&instance_vclock_storage)) + panic("Instance vclock can be initialized only once"); + vclock_copy(&instance_vclock_storage, vclock); +} + /** Shutdown box storage i.e. stop parts that need TX loop running. */ static void box_storage_shutdown() diff --git a/src/box/box.h b/src/box/box.h index b73f78e7f5..f3a069a7da 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -70,7 +70,7 @@ extern const struct vclock *box_vclock; * recovery this vclock points to the end of WAL, not to the current recovery * position. */ -extern struct vclock *instance_vclock; +extern const struct vclock *instance_vclock; /** * Name of the authentication method that is currently used on @@ -118,6 +118,18 @@ extern bool box_is_force_recovery; void box_init(void); +/** + * Set instance's vclock to the given value. Works only if the instance vclock + * isn't already set. It must be initialized manually and explicitly this way + * when the instance boots from a snapshot - snapshot rows have no LSNs, so + * setting the instance vclock manually is the only way. + * + * It has to be a "public" API of box, because the snapshot can be remote, i.e. + * coming from the applier. + */ +void +box_init_instance_vclock(const struct vclock *vclock); + /** Shutdown box storage i.e. stop parts that need TX loop running. */ void box_shutdown(void); -- GitLab