From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladimir Davydov Subject: [PATCH v2 05/10] box: move checkpointing to gc module Date: Sat, 8 Dec 2018 18:48:09 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: To: kostja@tarantool.org Cc: tarantool-patches@freelists.org List-ID: Garbage collection module seems to be the best way to accommodate the checkpoint daemon, but to move it there, we first need to move the code performing checkpoints there to avoid cross-dependency between box.cc and gc.c. --- src/box/box.cc | 44 +------------------------------------ src/box/gc.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/box/gc.h | 28 ++++++++++++++++-------- 3 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/box/box.cc b/src/box/box.cc index d146ec16..121ad787 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -90,11 +90,6 @@ static void title(const char *new_status) const struct vclock *box_vclock = &replicaset.vclock; /** - * Set if there's a fiber performing box_checkpoint() right now. - */ -static bool checkpoint_is_in_progress; - -/** * Set if backup is in progress, i.e. box_backup_start() was * called but box_backup_stop() hasn't been yet. */ @@ -2185,45 +2180,8 @@ box_checkpoint() /* Signal arrived before box.cfg{} */ if (! is_box_configured) return 0; - int rc = 0; - if (checkpoint_is_in_progress) { - diag_set(ClientError, ER_CHECKPOINT_IN_PROGRESS); - return -1; - } - checkpoint_is_in_progress = true; - /* create checkpoint files */ - latch_lock(&schema_lock); - if ((rc = engine_begin_checkpoint())) - goto end; - - struct vclock vclock; - if ((rc = wal_begin_checkpoint(&vclock))) - goto end; - if ((rc = engine_commit_checkpoint(&vclock))) - goto end; - - wal_commit_checkpoint(&vclock); - gc_add_checkpoint(&vclock); -end: - if (rc) - engine_abort_checkpoint(); - - latch_unlock(&schema_lock); - checkpoint_is_in_progress = false; - - /* - * Wait for background garbage collection that might - * have been triggered by this checkpoint to complete. - * Strictly speaking, it isn't necessary, but it - * simplifies testing as it guarantees that by the - * time box.snapshot() returns, all outdated checkpoint - * files have been removed. - */ - if (!rc) - gc_wait(); - - return rc; + return gc_checkpoint(); } int diff --git a/src/box/gc.c b/src/box/gc.c index 87273b8d..153ef65c 100644 --- a/src/box/gc.c +++ b/src/box/gc.c @@ -45,11 +45,14 @@ #include #include "diag.h" +#include "errcode.h" #include "fiber.h" #include "fiber_cond.h" +#include "latch.h" #include "say.h" #include "vclock.h" #include "cbus.h" +#include "schema.h" #include "engine.h" /* engine_collect_garbage() */ #include "wal.h" /* wal_collect_garbage() */ @@ -242,7 +245,11 @@ gc_schedule(void) fiber_wakeup(gc.fiber); } -void +/** + * Wait for background garbage collection scheduled prior + * to this point to complete. + */ +static void gc_wait(void) { unsigned scheduled = gc.scheduled; @@ -320,6 +327,65 @@ gc_add_checkpoint(const struct vclock *vclock) gc_schedule(); } +int +gc_checkpoint(void) +{ + int rc; + struct vclock vclock; + + if (gc.checkpoint_is_in_progress) { + diag_set(ClientError, ER_CHECKPOINT_IN_PROGRESS); + return -1; + } + gc.checkpoint_is_in_progress = true; + + /* + * We don't support DDL operations while making a checkpoint. + * Lock them out. + */ + latch_lock(&schema_lock); + + /* + * Rotate WAL and call engine callbacks to create a checkpoint + * on disk for each registered engine. + */ + rc = engine_begin_checkpoint(); + if (rc != 0) + goto out; + rc = wal_begin_checkpoint(&vclock); + if (rc != 0) + goto out; + rc = engine_commit_checkpoint(&vclock); + if (rc != 0) + goto out; + wal_commit_checkpoint(&vclock); + + /* + * Finally, track the newly created checkpoint in the garbage + * collector state. + */ + gc_add_checkpoint(&vclock); +out: + if (rc != 0) + engine_abort_checkpoint(); + + latch_unlock(&schema_lock); + gc.checkpoint_is_in_progress = false; + + /* + * Wait for background garbage collection that might + * have been triggered by this checkpoint to complete. + * Strictly speaking, it isn't necessary, but it + * simplifies testing as it guarantees that by the + * time box.snapshot() returns, all outdated checkpoint + * files have been removed. + */ + if (rc == 0) + gc_wait(); + + return rc; +} + void gc_ref_checkpoint(struct gc_checkpoint *checkpoint, struct gc_checkpoint_ref *ref, const char *format, ...) diff --git a/src/box/gc.h b/src/box/gc.h index a141ace6..84a441f2 100644 --- a/src/box/gc.h +++ b/src/box/gc.h @@ -31,6 +31,7 @@ * SUCH DAMAGE. */ +#include #include #include @@ -141,6 +142,10 @@ struct gc_state { * taken at that moment of time. */ unsigned completed, scheduled; + /** + * Set if there's a fiber making a checkpoint right now. + */ + bool checkpoint_is_in_progress; }; extern struct gc_state gc; @@ -192,13 +197,6 @@ void gc_free(void); /** - * Wait for background garbage collection scheduled prior - * to this point to complete. - */ -void -gc_wait(void); - -/** * Advance the garbage collector vclock to the given position. * Deactivate WAL consumers that need older data. */ @@ -217,14 +215,26 @@ void gc_set_min_checkpoint_count(int min_checkpoint_count); /** - * Track a new checkpoint in the garbage collector state. - * Note, this function may run garbage collector to remove + * Track an existing checkpoint in the garbage collector state. + * Note, this function may trigger garbage collection to remove * old checkpoints. */ void gc_add_checkpoint(const struct vclock *vclock); /** + * Make a checkpoint. + * + * This function runs engine/WAL callbacks to create a checkpoint + * on disk, then tracks the new checkpoint in the garbage collector + * state (see gc_add_checkpoint()). + * + * Returns 0 on success. On failure returns -1 and sets diag. + */ +int +gc_checkpoint(void); + +/** * Get a reference to @checkpoint and store it in @ref. * This will block the garbage collector from deleting * the checkpoint files until the reference is released -- 2.11.0