diff --git a/src/box/vinyl.c b/src/box/vinyl.c index c0f28ed26f81..de4a06c494f3 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -755,18 +755,8 @@ vinyl_index_open(struct index *index) /* * Add the new LSM tree to the scheduler so that it can * be dumped and compacted. - * - * Note, during local recovery an LSM tree may be marked - * as dropped, which means that it will be dropped before - * recovery is complete. In this case there's no need in - * letting the scheduler know about it. */ - if (!lsm->is_dropped) - vy_scheduler_add_lsm(&env->scheduler, lsm); - else - assert(env->status == VINYL_INITIAL_RECOVERY_LOCAL || - env->status == VINYL_FINAL_RECOVERY_LOCAL); - return 0; + return vy_scheduler_add_lsm(&env->scheduler, lsm); } static void @@ -836,8 +826,6 @@ vinyl_index_abort_create(struct index *index) return; } - vy_scheduler_remove_lsm(&env->scheduler, lsm); - lsm->is_dropped = true; vy_log_tx_begin(); @@ -891,8 +879,6 @@ vinyl_index_commit_drop(struct index *index, int64_t lsn) if (env->status == VINYL_FINAL_RECOVERY_LOCAL && lsm->is_dropped) return; - vy_scheduler_remove_lsm(&env->scheduler, lsm); - lsm->is_dropped = true; vy_log_tx_begin(); diff --git a/src/box/vy_lsm.c b/src/box/vy_lsm.c index 8fba1792a674..aa4bce9eb34e 100644 --- a/src/box/vy_lsm.c +++ b/src/box/vy_lsm.c @@ -45,6 +45,7 @@ #include "say.h" #include "schema.h" #include "tuple.h" +#include "trigger.h" #include "vy_log.h" #include "vy_mem.h" #include "vy_range.h" @@ -207,6 +208,7 @@ vy_lsm_new(struct vy_lsm_env *lsm_env, struct vy_cache_env *cache_env, lsm->group_id = group_id; lsm->opts = index_def->opts; vy_lsm_read_set_new(&lsm->read_set); + rlist_create(&lsm->on_destroy); lsm_env->lsm_count++; return lsm; @@ -244,6 +246,8 @@ vy_range_tree_free_cb(vy_range_tree_t *t, struct vy_range *range, void *arg) void vy_lsm_delete(struct vy_lsm *lsm) { + trigger_run(&lsm->on_destroy, lsm); + assert(heap_node_is_stray(&lsm->in_dump)); assert(heap_node_is_stray(&lsm->in_compaction)); assert(vy_lsm_read_set_empty(&lsm->read_set)); diff --git a/src/box/vy_lsm.h b/src/box/vy_lsm.h index c8b0e2974c58..3b553ea570c3 100644 --- a/src/box/vy_lsm.h +++ b/src/box/vy_lsm.h @@ -312,6 +312,20 @@ struct vy_lsm { * this LSM tree. */ vy_lsm_read_set_t read_set; + /** + * Triggers run when the last reference to this LSM tree + * is dropped and the LSM tree is about to be destroyed. + * A pointer to this LSM tree is passed to the trigger + * callback in the 'event' argument. + * + * For instance, this trigger is used to remove a dropped + * LSM tree from the scheduler before it gets destroyed. + * Since each dump/compaction task takes a reference to + * the target index, this means that a dropped index will + * not get destroyed until all tasks scheduled for it have + * been completed. + */ + struct rlist on_destroy; }; /** Extract vy_lsm from an index object. */ diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c index f3bded209f6a..ee361c31f550 100644 --- a/src/box/vy_scheduler.c +++ b/src/box/vy_scheduler.c @@ -510,35 +510,47 @@ vy_scheduler_reset_stat(struct vy_scheduler *scheduler) stat->compaction_output = 0; } -void +static void +vy_scheduler_on_delete_lsm(struct trigger *trigger, void *event) +{ + struct vy_lsm *lsm = event; + struct vy_scheduler *scheduler = trigger->data; + assert(! heap_node_is_stray(&lsm->in_dump)); + assert(! heap_node_is_stray(&lsm->in_compaction)); + vy_dump_heap_delete(&scheduler->dump_heap, lsm); + vy_compaction_heap_delete(&scheduler->compaction_heap, lsm); + trigger_clear(trigger); + free(trigger); +} + +int vy_scheduler_add_lsm(struct vy_scheduler *scheduler, struct vy_lsm *lsm) { - assert(!lsm->is_dropped); assert(heap_node_is_stray(&lsm->in_dump)); assert(heap_node_is_stray(&lsm->in_compaction)); + /* + * Register a trigger that will remove this LSM tree from + * the scheduler queues on destruction. + */ + struct trigger *trigger = malloc(sizeof(*trigger)); + if (trigger == NULL) { + diag_set(OutOfMemory, sizeof(*trigger), "malloc", "trigger"); + return -1; + } + trigger_create(trigger, vy_scheduler_on_delete_lsm, scheduler, NULL); + trigger_add(&lsm->on_destroy, trigger); + /* + * Add this LSM tree to the scheduler queues so that it + * can be dumped and compacted in a timely manner. + */ vy_dump_heap_insert(&scheduler->dump_heap, lsm); vy_compaction_heap_insert(&scheduler->compaction_heap, lsm); -} - -void -vy_scheduler_remove_lsm(struct vy_scheduler *scheduler, struct vy_lsm *lsm) -{ - assert(!lsm->is_dropped); - assert(! heap_node_is_stray(&lsm->in_dump)); - assert(! heap_node_is_stray(&lsm->in_compaction)); - vy_dump_heap_delete(&scheduler->dump_heap, lsm); - vy_compaction_heap_delete(&scheduler->compaction_heap, lsm); + return 0; } static void vy_scheduler_update_lsm(struct vy_scheduler *scheduler, struct vy_lsm *lsm) { - if (lsm->is_dropped) { - /* Dropped LSM trees are exempted from scheduling. */ - assert(heap_node_is_stray(&lsm->in_dump)); - assert(heap_node_is_stray(&lsm->in_compaction)); - return; - } assert(! heap_node_is_stray(&lsm->in_dump)); assert(! heap_node_is_stray(&lsm->in_compaction)); vy_dump_heap_update(&scheduler->dump_heap, lsm); @@ -1267,15 +1279,9 @@ vy_task_dump_abort(struct vy_task *task) /* The iterator has been cleaned up in a worker thread. */ task->wi->iface->close(task->wi); - /* - * It's no use alerting the user if the server is - * shutting down or the LSM tree was dropped. - */ - if (!lsm->is_dropped) { - struct error *e = diag_last_error(&task->diag); - error_log(e); - say_error("%s: dump failed", vy_lsm_name(lsm)); - } + struct error *e = diag_last_error(&task->diag); + error_log(e); + say_error("%s: dump failed", vy_lsm_name(lsm)); vy_run_discard(task->new_run); @@ -1287,18 +1293,6 @@ vy_task_dump_abort(struct vy_task *task) assert(scheduler->dump_task_count > 0); scheduler->dump_task_count--; - - /* - * If the LSM tree was dropped during dump, we abort - * the dump task, but we should still poke the scheduler - * to check if the current dump round is complete. - * If we don't and this LSM tree happens to be the last - * one of the current generation, the scheduler will - * never be notified about dump completion and hence - * memory will never be released. - */ - if (lsm->is_dropped) - vy_scheduler_complete_dump(scheduler); } /** @@ -1317,7 +1311,6 @@ vy_task_dump_new(struct vy_scheduler *scheduler, struct vy_worker *worker, .abort = vy_task_dump_abort, }; - assert(!lsm->is_dropped); assert(!lsm->is_dumping); assert(lsm->pin_count == 0); assert(vy_lsm_generation(lsm) == scheduler->dump_generation); @@ -1602,16 +1595,10 @@ vy_task_compaction_abort(struct vy_task *task) /* The iterator has been cleaned up in worker. */ task->wi->iface->close(task->wi); - /* - * It's no use alerting the user if the server is - * shutting down or the LSM tree was dropped. - */ - if (!lsm->is_dropped) { - struct error *e = diag_last_error(&task->diag); - error_log(e); - say_error("%s: failed to compact range %s", - vy_lsm_name(lsm), vy_range_str(range)); - } + struct error *e = diag_last_error(&task->diag); + error_log(e); + say_error("%s: failed to compact range %s", + vy_lsm_name(lsm), vy_range_str(range)); vy_run_discard(task->new_run); @@ -1629,7 +1616,6 @@ vy_task_compaction_new(struct vy_scheduler *scheduler, struct vy_worker *worker, .complete = vy_task_compaction_complete, .abort = vy_task_compaction_abort, }; - assert(!lsm->is_dropped); struct vy_range *range = vy_range_heap_top(&lsm->range_heap); assert(range != NULL); @@ -1945,12 +1931,6 @@ vy_task_complete(struct vy_task *task) assert(scheduler->stat.tasks_inprogress > 0); scheduler->stat.tasks_inprogress--; - if (task->lsm->is_dropped) { - if (task->ops->abort) - task->ops->abort(task); - goto out; - } - struct diag *diag = &task->diag; if (task->is_failed) { assert(!diag_is_empty(diag)); @@ -1967,7 +1947,6 @@ vy_task_complete(struct vy_task *task) diag_move(diag_get(), diag); goto fail; } -out: scheduler->stat.tasks_completed++; return 0; fail: diff --git a/src/box/vy_scheduler.h b/src/box/vy_scheduler.h index 2d4352d75169..bc953975ec7f 100644 --- a/src/box/vy_scheduler.h +++ b/src/box/vy_scheduler.h @@ -194,16 +194,12 @@ vy_scheduler_reset_stat(struct vy_scheduler *scheduler); /** * Add an LSM tree to scheduler dump/compaction queues. + * When the LSM tree is destroyed, it will be removed + * from the queues automatically. */ -void +int vy_scheduler_add_lsm(struct vy_scheduler *, struct vy_lsm *); -/** - * Remove an LSM tree from scheduler dump/compaction queues. - */ -void -vy_scheduler_remove_lsm(struct vy_scheduler *, struct vy_lsm *); - /** * Trigger dump of all currently existing in-memory trees. */