[PATCH 2/6] engine: pass vclock instead of lsn to collect_garbage callback

Vladimir Davydov vdavydov.dev at gmail.com
Sun Nov 25 16:48:09 MSK 2018


First, this is consistent with other engine callbacks, such as
checkpoint or backup.

Second, a vclock can be used as a search key in a vclock set,
which in turn can make code more straightforward, e.g. look how
this patch simplifies vy_log_prev_checkpoint().
---
 src/box/box.cc         |  2 +-
 src/box/engine.c       |  9 +++++----
 src/box/engine.h       |  9 +++++----
 src/box/gc.c           |  7 ++-----
 src/box/memtx_engine.c |  5 +++--
 src/box/vinyl.c        |  9 ++++-----
 src/box/vy_log.c       | 36 ++++++++++++++++--------------------
 src/box/vy_log.h       |  4 ++--
 src/box/wal.c          | 41 +++++++++++++++++++++++------------------
 src/box/wal.h          |  9 +++++----
 10 files changed, 66 insertions(+), 65 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index ab6658fb..21b84991 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -2129,7 +2129,7 @@ box_cfg_xc(void)
 	enum wal_mode wal_mode = box_check_wal_mode(cfg_gets("wal_mode"));
 	if (wal_init(wal_mode, cfg_gets("wal_dir"), wal_max_rows,
 		     wal_max_size, &INSTANCE_UUID, &replicaset.vclock,
-		     vclock_sum(&first_checkpoint->vclock))) {
+		     &first_checkpoint->vclock) != 0) {
 		diag_raise();
 	}
 	gc_set_wal_watcher();
diff --git a/src/box/engine.c b/src/box/engine.c
index 2a30dcdd..409479a3 100644
--- a/src/box/engine.c
+++ b/src/box/engine.c
@@ -148,11 +148,11 @@ engine_abort_checkpoint(void)
 }
 
 int
-engine_collect_garbage(int64_t lsn)
+engine_collect_garbage(const struct vclock *vclock)
 {
 	struct engine *engine;
 	engine_foreach(engine) {
-		if (engine->vtab->collect_garbage(engine, lsn) < 0)
+		if (engine->vtab->collect_garbage(engine, vclock) < 0)
 			return -1;
 	}
 	return 0;
@@ -317,10 +317,11 @@ generic_engine_abort_checkpoint(struct engine *engine)
 }
 
 int
-generic_engine_collect_garbage(struct engine *engine, int64_t lsn)
+generic_engine_collect_garbage(struct engine *engine,
+			       const struct vclock *vclock)
 {
 	(void)engine;
-	(void)lsn;
+	(void)vclock;
 	return 0;
 }
 
diff --git a/src/box/engine.h b/src/box/engine.h
index 5b96c744..87c84e51 100644
--- a/src/box/engine.h
+++ b/src/box/engine.h
@@ -156,7 +156,7 @@ struct engine_vtab {
 	void (*abort_checkpoint)(struct engine *);
 	/**
 	 * Remove files that are not needed to recover
-	 * from checkpoint with @lsn or newer.
+	 * from checkpoint @vclock or newer.
 	 *
 	 * If this function returns a non-zero value, garbage
 	 * collection is aborted, i.e. this method isn't called
@@ -166,7 +166,8 @@ struct engine_vtab {
 	 * fails to delete a snapshot file, because we recover
 	 * checkpoint list by scanning the snapshot directory.
 	 */
-	int (*collect_garbage)(struct engine *engine, int64_t lsn);
+	int (*collect_garbage)(struct engine *engine,
+			       const struct vclock *vclock);
 	/**
 	 * Backup callback. It is supposed to call @cb for each file
 	 * that needs to be backed up in order to restore from the
@@ -337,7 +338,7 @@ void
 engine_abort_checkpoint(void);
 
 int
-engine_collect_garbage(int64_t lsn);
+engine_collect_garbage(const struct vclock *vclock);
 
 int
 engine_backup(const struct vclock *vclock, engine_backup_cb cb, void *cb_arg);
@@ -369,7 +370,7 @@ int generic_engine_begin_checkpoint(struct engine *);
 int generic_engine_wait_checkpoint(struct engine *, const struct vclock *);
 void generic_engine_commit_checkpoint(struct engine *, const struct vclock *);
 void generic_engine_abort_checkpoint(struct engine *);
-int generic_engine_collect_garbage(struct engine *, int64_t);
+int generic_engine_collect_garbage(struct engine *, const struct vclock *);
 int generic_engine_backup(struct engine *, const struct vclock *,
 			  engine_backup_cb, void *);
 void generic_engine_memory_stat(struct engine *, struct engine_memory_stat *);
diff --git a/src/box/gc.c b/src/box/gc.c
index cefe1553..55c36d15 100644
--- a/src/box/gc.c
+++ b/src/box/gc.c
@@ -201,9 +201,6 @@ gc_run(void)
 	if (!run_engine_gc && !run_wal_gc)
 		return; /* nothing to do */
 
-	int64_t wal_lsn = vclock_sum(vclock);
-	int64_t checkpoint_lsn = vclock_sum(&checkpoint->vclock);
-
 	/*
 	 * Engine callbacks may sleep, because they use coio for
 	 * removing files. Make sure we won't try to remove the
@@ -220,14 +217,14 @@ gc_run(void)
 	 */
 	int rc = 0;
 	if (run_engine_gc)
-		rc = engine_collect_garbage(checkpoint_lsn);
+		rc = engine_collect_garbage(&checkpoint->vclock);
 	/*
 	 * Run wal_collect_garbage() even if we don't need to
 	 * delete any WAL files, because we have to apprise
 	 * the WAL thread of the oldest checkpoint signature.
 	 */
 	if (rc == 0)
-		wal_collect_garbage(wal_lsn, checkpoint_lsn);
+		wal_collect_garbage(vclock, &checkpoint->vclock);
 	latch_unlock(&gc.latch);
 }
 
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index 28afb324..9e05ecf6 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -822,7 +822,7 @@ memtx_engine_abort_checkpoint(struct engine *engine)
 }
 
 static int
-memtx_engine_collect_garbage(struct engine *engine, int64_t lsn)
+memtx_engine_collect_garbage(struct engine *engine, const struct vclock *vclock)
 {
 	struct memtx_engine *memtx = (struct memtx_engine *)engine;
 	/*
@@ -833,7 +833,8 @@ memtx_engine_collect_garbage(struct engine *engine, int64_t lsn)
 	 * That said, we have to abort garbage collection if we
 	 * fail to delete a snap file.
 	 */
-	if (xdir_collect_garbage(&memtx->snap_dir, lsn, XDIR_GC_USE_COIO) != 0)
+	if (xdir_collect_garbage(&memtx->snap_dir, vclock_sum(vclock),
+				 XDIR_GC_USE_COIO) != 0)
 		return -1;
 
 	return 0;
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index ce81c6ad..1794489d 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -3286,21 +3286,20 @@ vy_gc(struct vy_env *env, struct vy_recovery *recovery,
 }
 
 static int
-vinyl_engine_collect_garbage(struct engine *engine, int64_t lsn)
+vinyl_engine_collect_garbage(struct engine *engine, const struct vclock *vclock)
 {
 	struct vy_env *env = vy_env(engine);
 
 	/* Cleanup old metadata log files. */
-	vy_log_collect_garbage(lsn);
+	vy_log_collect_garbage(vclock);
 
 	/* Cleanup run files. */
-	int64_t signature = vy_log_signature();
-	struct vy_recovery *recovery = vy_recovery_new(signature, 0);
+	struct vy_recovery *recovery = vy_recovery_new(vy_log_signature(), 0);
 	if (recovery == NULL) {
 		say_error("failed to recover vylog for garbage collection");
 		return 0;
 	}
-	vy_gc(env, recovery, VY_GC_DROPPED, lsn);
+	vy_gc(env, recovery, VY_GC_DROPPED, vclock_sum(vclock));
 	vy_recovery_delete(recovery);
 	return 0;
 }
diff --git a/src/box/vy_log.c b/src/box/vy_log.c
index 8a8f9d70..c9e0713c 100644
--- a/src/box/vy_log.c
+++ b/src/box/vy_log.c
@@ -202,22 +202,16 @@ vy_log_filename(int64_t signature)
 }
 
 /**
- * Return the lsn of the checkpoint that was taken
- * before the given lsn.
+ * Return the vclock of the checkpoint that was taken
+ * before the given vclock.
  */
-static int64_t
-vy_log_prev_checkpoint(int64_t lsn)
+static const struct vclock *
+vy_log_prev_checkpoint(const struct vclock *vclock)
 {
-	int64_t ret = -1;
-	for (struct vclock *vclock = vclockset_last(&vy_log.dir.index);
-	     vclock != NULL;
-	     vclock = vclockset_prev(&vy_log.dir.index, vclock)) {
-		if (vclock_sum(vclock) < lsn) {
-			ret = vclock_sum(vclock);
-			break;
-		}
-	}
-	return ret;
+	struct vclock *prev = vclockset_psearch(&vy_log.dir.index, vclock);
+	if (prev != NULL && vclock_sum(prev) == vclock_sum(vclock))
+		prev = vclockset_prev(&vy_log.dir.index, prev);
+	return prev;
 }
 
 /** An snprint-style function to print a log record. */
@@ -1076,14 +1070,16 @@ fail:
 }
 
 void
-vy_log_collect_garbage(int64_t signature)
+vy_log_collect_garbage(const struct vclock *vclock)
 {
 	/*
 	 * Always keep the previous file, because
 	 * it is still needed for backups.
 	 */
-	signature = vy_log_prev_checkpoint(signature);
-	xdir_collect_garbage(&vy_log.dir, signature, XDIR_GC_USE_COIO);
+	vclock = vy_log_prev_checkpoint(vclock);
+	if (vclock == NULL)
+		return;
+	xdir_collect_garbage(&vy_log.dir, vclock_sum(vclock), XDIR_GC_USE_COIO);
 }
 
 int64_t
@@ -1099,10 +1095,10 @@ vy_log_backup_path(const struct vclock *vclock)
 	 * Use the previous log file, because the current one
 	 * contains records written after the last checkpoint.
 	 */
-	int64_t lsn = vy_log_prev_checkpoint(vclock_sum(vclock));
-	if (lsn < 0)
+	vclock = vy_log_prev_checkpoint(vclock);
+	if (vclock == NULL)
 		return NULL;
-	const char *path = vy_log_filename(lsn);
+	const char *path = vy_log_filename(vclock_sum(vclock));
 	if (access(path, F_OK) == -1 && errno == ENOENT)
 		return NULL; /* vinyl not used */
 	return path;
diff --git a/src/box/vy_log.h b/src/box/vy_log.h
index 7718d9c6..70e25245 100644
--- a/src/box/vy_log.h
+++ b/src/box/vy_log.h
@@ -455,10 +455,10 @@ vy_log_rotate(const struct vclock *vclock);
 
 /**
  * Remove metadata log files that are not needed to recover
- * from the snapshot with the given signature or newer.
+ * from checkpoint @vclock.
  */
 void
-vy_log_collect_garbage(int64_t signature);
+vy_log_collect_garbage(const struct vclock *vclock);
 
 /**
  * Return the signature of the newest vylog to the time.
diff --git a/src/box/wal.c b/src/box/wal.c
index 673762a6..cbf2c121 100644
--- a/src/box/wal.c
+++ b/src/box/wal.c
@@ -120,11 +120,11 @@ struct wal_writer
 	 */
 	struct vclock vclock;
 	/**
-	 * Signature of the oldest checkpoint available on the instance.
+	 * VClock of the oldest checkpoint available on the instance.
 	 * The WAL writer must not delete WAL files that are needed to
 	 * recover from it even if it is running out of disk space.
 	 */
-	int64_t checkpoint_lsn;
+	struct vclock checkpoint_vclock;
 	/** The current WAL file. */
 	struct xlog current_wal;
 	/**
@@ -295,7 +295,8 @@ static void
 wal_writer_create(struct wal_writer *writer, enum wal_mode wal_mode,
 		  const char *wal_dirname, int64_t wal_max_rows,
 		  int64_t wal_max_size, const struct tt_uuid *instance_uuid,
-		  const struct vclock *vclock, int64_t checkpoint_lsn)
+		  const struct vclock *vclock,
+		  const struct vclock *checkpoint_vclock)
 {
 	writer->wal_mode = wal_mode;
 	writer->wal_max_rows = wal_max_rows;
@@ -311,11 +312,8 @@ wal_writer_create(struct wal_writer *writer, enum wal_mode wal_mode,
 	stailq_create(&writer->rollback);
 	cmsg_init(&writer->in_rollback, NULL);
 
-	/* Create and fill writer->vclock. */
-	vclock_create(&writer->vclock);
 	vclock_copy(&writer->vclock, vclock);
-
-	writer->checkpoint_lsn = checkpoint_lsn;
+	vclock_copy(&writer->checkpoint_vclock, checkpoint_vclock);
 	rlist_create(&writer->watchers);
 }
 
@@ -421,14 +419,14 @@ wal_open(struct wal_writer *writer)
 int
 wal_init(enum wal_mode wal_mode, const char *wal_dirname, int64_t wal_max_rows,
 	 int64_t wal_max_size, const struct tt_uuid *instance_uuid,
-	 const struct vclock *vclock, int64_t first_checkpoint_lsn)
+	 const struct vclock *vclock, const struct vclock *first_checkpoint_vclock)
 {
 	assert(wal_max_rows > 1);
 
 	struct wal_writer *writer = &wal_writer_singleton;
 	wal_writer_create(writer, wal_mode, wal_dirname, wal_max_rows,
 			  wal_max_size, instance_uuid, vclock,
-			  first_checkpoint_lsn);
+			  first_checkpoint_vclock);
 
 	/*
 	 * Scan the WAL directory to build an index of all
@@ -546,8 +544,8 @@ wal_checkpoint(struct vclock *vclock, bool rotate)
 struct wal_gc_msg
 {
 	struct cbus_call_msg base;
-	int64_t wal_lsn;
-	int64_t checkpoint_lsn;
+	const struct vclock *wal_vclock;
+	const struct vclock *checkpoint_vclock;
 };
 
 static int
@@ -555,20 +553,21 @@ wal_collect_garbage_f(struct cbus_call_msg *data)
 {
 	struct wal_writer *writer = &wal_writer_singleton;
 	struct wal_gc_msg *msg = (struct wal_gc_msg *)data;
-	writer->checkpoint_lsn = msg->checkpoint_lsn;
-	xdir_collect_garbage(&writer->wal_dir, msg->wal_lsn, 0);
+	vclock_copy(&writer->checkpoint_vclock, msg->checkpoint_vclock);
+	xdir_collect_garbage(&writer->wal_dir, vclock_sum(msg->wal_vclock), 0);
 	return 0;
 }
 
 void
-wal_collect_garbage(int64_t wal_lsn, int64_t checkpoint_lsn)
+wal_collect_garbage(const struct vclock *wal_vclock,
+		    const struct vclock *checkpoint_vclock)
 {
 	struct wal_writer *writer = &wal_writer_singleton;
 	if (writer->wal_mode == WAL_NONE)
 		return;
 	struct wal_gc_msg msg;
-	msg.wal_lsn = wal_lsn;
-	msg.checkpoint_lsn = checkpoint_lsn;
+	msg.wal_vclock = wal_vclock;
+	msg.checkpoint_vclock = checkpoint_vclock;
 	bool cancellable = fiber_set_cancellable(false);
 	cbus_call(&wal_thread.wal_pipe, &wal_thread.tx_prio_pipe, &msg.base,
 		  wal_collect_garbage_f, NULL, TIMEOUT_INFINITY);
@@ -643,6 +642,12 @@ wal_fallocate(struct wal_writer *writer, size_t len)
 	struct errinj *errinj = errinj(ERRINJ_WAL_FALLOCATE, ERRINJ_INT);
 
 	/*
+	 * Max LSN that can be collected in case of ENOSPC -
+	 * we must not delete WALs necessary for recovery.
+	 */
+	int64_t gc_lsn = vclock_sum(&writer->checkpoint_vclock);
+
+	/*
 	 * The actual write size can be greater than the sum size
 	 * of encoded rows (compression, fixheaders). Double the
 	 * given length to get a rough upper bound estimate.
@@ -662,7 +667,7 @@ retry:
 	}
 	if (errno != ENOSPC)
 		goto error;
-	if (!xdir_has_garbage(&writer->wal_dir, writer->checkpoint_lsn))
+	if (!xdir_has_garbage(&writer->wal_dir, gc_lsn))
 		goto error;
 
 	if (warn_no_space) {
@@ -674,7 +679,7 @@ retry:
 	struct diag diag;
 	diag_create(&diag);
 	diag_move(diag_get(), &diag);
-	if (xdir_collect_garbage(&writer->wal_dir, writer->checkpoint_lsn,
+	if (xdir_collect_garbage(&writer->wal_dir, gc_lsn,
 				 XDIR_GC_REMOVE_ONE) != 0) {
 		diag_move(&diag, diag_get());
 		goto error;
diff --git a/src/box/wal.h b/src/box/wal.h
index d4a37c55..808af76e 100644
--- a/src/box/wal.h
+++ b/src/box/wal.h
@@ -58,7 +58,7 @@ wal_thread_start();
 int
 wal_init(enum wal_mode wal_mode, const char *wal_dirname, int64_t wal_max_rows,
 	 int64_t wal_max_size, const struct tt_uuid *instance_uuid,
-	 const struct vclock *vclock, int64_t first_checkpoint_lsn);
+	 const struct vclock *vclock, const struct vclock *first_checkpoint_vclock);
 
 void
 wal_thread_stop();
@@ -175,14 +175,15 @@ int
 wal_checkpoint(struct vclock *vclock, bool rotate);
 
 /**
- * Remove all WAL files whose signature is less than @wal_lsn.
- * Update the oldest checkpoint signature with @checkpoint_lsn.
+ * Remove all WAL files whose signature is less than @wal_vclock.
+ * Update the oldest checkpoint signature with @checkpoint_vclock.
  * WAL thread will delete WAL files that are not needed to
  * recover from the oldest checkpoint if it runs out of disk
  * space.
  */
 void
-wal_collect_garbage(int64_t wal_lsn, int64_t checkpoint_lsn);
+wal_collect_garbage(const struct vclock *wal_vclock,
+		    const struct vclock *checkpoint_vclock);
 
 void
 wal_init_vy_log();
-- 
2.11.0




More information about the Tarantool-patches mailing list