diff --git a/src/box/box.cc b/src/box/box.cc index 80fda4c587925f6b4dd22dac5c1f94c193a6990c..4e921f769179cde3e5c8b3432a3aa8199ef35b7c 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -614,6 +614,11 @@ void box_set_too_long_threshold(void) { too_long_threshold = cfg_getd("too_long_threshold"); + + struct vinyl_engine *vinyl; + vinyl = (struct vinyl_engine *)engine_by_name("vinyl"); + assert(vinyl != NULL); + vinyl_engine_set_too_long_threshold(vinyl, too_long_threshold); } void @@ -1432,10 +1437,10 @@ engine_init() cfg_geti64("vinyl_cache"), cfg_geti("vinyl_read_threads"), cfg_geti("vinyl_write_threads"), - cfg_getd("vinyl_timeout"), cfg_geti("force_recovery")); engine_register((struct engine *)vinyl); box_set_vinyl_max_tuple_size(); + box_set_vinyl_timeout(); } /** diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 5fafa4ebc39dd6e1cfee9165fc6e1bdd3b1651e3..f4dc48d532a3722a00007108461e71b2d3123405 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -149,6 +149,11 @@ struct vy_env { size_t memory; /** Max time a transaction may wait for memory. */ double timeout; + /** + * If read of a single statement takes longer than + * the given value, warn about it in the log. + */ + double too_long_threshold; /** Max number of threads used for reading. */ int read_threads; /** Max number of threads used for writing. */ @@ -1246,8 +1251,8 @@ vy_index_get(struct vy_env *env, struct vy_tx *tx, struct vy_index *index, } struct vy_read_iterator itr; - vy_read_iterator_open(&itr, &env->run_env, index, tx, - ITER_EQ, vykey, p_read_view); + vy_read_iterator_open(&itr, &env->run_env, index, tx, ITER_EQ, vykey, + p_read_view, env->too_long_threshold); int rc = vy_read_iterator_next(&itr, result); tuple_unref(vykey); if (*result != NULL) @@ -2570,8 +2575,8 @@ vy_squash_schedule(struct vy_index *index, struct tuple *stmt, void /* struct vy_env */ *arg); static struct vy_env * -vy_env_new(const char *path, size_t memory, size_t cache, int read_threads, - int write_threads, double timeout, bool force_recovery) +vy_env_new(const char *path, size_t memory, size_t cache, + int read_threads, int write_threads, bool force_recovery) { enum { KB = 1000, MB = 1000 * 1000 }; static int64_t dump_bandwidth_buckets[] = { @@ -2596,7 +2601,8 @@ vy_env_new(const char *path, size_t memory, size_t cache, int read_threads, memset(e, 0, sizeof(*e)); e->status = VINYL_OFFLINE; e->memory = memory; - e->timeout = timeout; + e->timeout = TIMEOUT_INFINITY; + e->too_long_threshold = TIMEOUT_INFINITY; e->read_threads = read_threads; e->write_threads = write_threads; e->force_recovery = force_recovery; @@ -2689,8 +2695,7 @@ vy_env_delete(struct vy_env *e) struct vinyl_engine * vinyl_engine_new(const char *dir, size_t memory, size_t cache, - int read_threads, int write_threads, double timeout, - bool force_recovery) + int read_threads, int write_threads, bool force_recovery) { struct vinyl_engine *vinyl = calloc(1, sizeof(*vinyl)); if (vinyl == NULL) { @@ -2700,7 +2705,7 @@ vinyl_engine_new(const char *dir, size_t memory, size_t cache, } vinyl->env = vy_env_new(dir, memory, cache, read_threads, - write_threads, timeout, force_recovery); + write_threads, force_recovery); if (vinyl->env == NULL) { free(vinyl); return NULL; @@ -2732,6 +2737,13 @@ vinyl_engine_set_timeout(struct vinyl_engine *vinyl, double timeout) vinyl->env->timeout = timeout; } +void +vinyl_engine_set_too_long_threshold(struct vinyl_engine *vinyl, + double too_long_threshold) +{ + vinyl->env->too_long_threshold = too_long_threshold; +} + /** }}} Environment */ /* {{{ Checkpoint */ @@ -3521,7 +3533,8 @@ vy_squash_process(struct vy_squash *squash) * prepared, but not committed statements. */ vy_read_iterator_open(&itr, &env->run_env, index, NULL, ITER_EQ, - squash->stmt, &env->xm->p_committed_read_view); + squash->stmt, &env->xm->p_committed_read_view, + env->too_long_threshold); struct tuple *result; int rc = vy_read_iterator_next(&itr, &result); if (rc == 0 && result != NULL) @@ -3908,7 +3921,8 @@ vinyl_index_create_iterator(struct index *base, enum iterator_type type, vy_read_iterator_open(&it->iterator, &env->run_env, index, tx, type, it->key, - (const struct vy_read_view **)&tx->read_view); + (const struct vy_read_view **)&tx->read_view, + env->too_long_threshold); return (struct iterator *)it; } diff --git a/src/box/vinyl.h b/src/box/vinyl.h index c8c07dfd99158ca7727bbd670963f150628ed359..63add146b60c8e73d448518b3aebf62b9927e429 100644 --- a/src/box/vinyl.h +++ b/src/box/vinyl.h @@ -43,8 +43,7 @@ struct vinyl_engine; struct vinyl_engine * vinyl_engine_new(const char *dir, size_t memory, size_t cache, - int read_threads, int write_threads, double timeout, - bool force_recovery); + int read_threads, int write_threads, bool force_recovery); /** * Engine introspection (box.info.vinyl()) @@ -64,6 +63,13 @@ vinyl_engine_set_max_tuple_size(struct vinyl_engine *vinyl, size_t max_size); void vinyl_engine_set_timeout(struct vinyl_engine *vinyl, double timeout); +/** + * Update too_long_threshold. + */ +void +vinyl_engine_set_too_long_threshold(struct vinyl_engine *vinyl, + double too_long_threshold); + #ifdef __cplusplus } /* extern "C" */ @@ -71,12 +77,11 @@ vinyl_engine_set_timeout(struct vinyl_engine *vinyl, double timeout); static inline struct vinyl_engine * vinyl_engine_new_xc(const char *dir, size_t memory, size_t cache, - int read_threads, int write_threads, double timeout, - bool force_recovery) + int read_threads, int write_threads, bool force_recovery) { struct vinyl_engine *vinyl; vinyl = vinyl_engine_new(dir, memory, cache, read_threads, - write_threads, timeout, force_recovery); + write_threads, force_recovery); if (vinyl == NULL) diag_raise(); return vinyl; diff --git a/src/box/vy_read_iterator.c b/src/box/vy_read_iterator.c index f9b85802d9ebdafdd4f12eac38d003061ec4a8e8..14ac9f7546e305b89d5c98f81da9bc7e84500dad 100644 --- a/src/box/vy_read_iterator.c +++ b/src/box/vy_read_iterator.c @@ -575,7 +575,7 @@ void vy_read_iterator_open(struct vy_read_iterator *itr, struct vy_run_env *run_env, struct vy_index *index, struct vy_tx *tx, enum iterator_type iterator_type, struct tuple *key, - const struct vy_read_view **rv) + const struct vy_read_view **rv, double too_long_threshold) { memset(itr, 0, sizeof(*itr)); @@ -585,6 +585,7 @@ vy_read_iterator_open(struct vy_read_iterator *itr, struct vy_run_env *run_env, itr->iterator_type = iterator_type; itr->key = key; itr->read_view = rv; + itr->too_long_threshold = too_long_threshold; if (tuple_field_count(key) == 0) { /* @@ -888,8 +889,15 @@ vy_read_iterator_next(struct vy_read_iterator *itr, struct tuple **result) if (prev_key != NULL) tuple_unref(prev_key); - latency_collect(&index->stat.latency, - ev_monotonic_now(loop()) - start_time); + ev_tstamp latency = ev_monotonic_now(loop()) - start_time; + latency_collect(&index->stat.latency, latency); + + if (latency > itr->too_long_threshold) { + say_warn("%s: select(%s, %s) => %s took too long: %.3f sec", + vy_index_name(index), tuple_str(itr->key), + iterator_type_strs[itr->iterator_type], + vy_stmt_str(itr->last_stmt), latency); + } return rc; } diff --git a/src/box/vy_read_iterator.h b/src/box/vy_read_iterator.h index 51ebc33db0b47aecf8e11a0074db112f4ca5f704..344e457c8b56ae9cbf238f00295585c8cb904809 100644 --- a/src/box/vy_read_iterator.h +++ b/src/box/vy_read_iterator.h @@ -59,6 +59,11 @@ struct vy_read_iterator { struct tuple *key; /** Read view the iterator lives in. */ const struct vy_read_view **read_view; + /** + * If a read iteration takes longer than the given value, + * warn about it in the log. + */ + double too_long_threshold; /** * Set if the resulting statement needs to be * checked to match the search key. @@ -128,7 +133,7 @@ void vy_read_iterator_open(struct vy_read_iterator *itr, struct vy_run_env *run_env, struct vy_index *index, struct vy_tx *tx, enum iterator_type iterator_type, struct tuple *key, - const struct vy_read_view **rv); + const struct vy_read_view **rv, double too_long_threshold); /** * Get the next statement with another key, or start the iterator, diff --git a/test/vinyl/errinj.result b/test/vinyl/errinj.result index 4a5bc14d07c71c81aeff4d8491e3b1900ad15796..9f4c82c178b96e8eee1dfe3d81ea1d39112fcd8d 100644 --- a/test/vinyl/errinj.result +++ b/test/vinyl/errinj.result @@ -282,6 +282,40 @@ s:select() - [9, 'test str9'] - [10, 'test str10'] ... +-- gh-2871: check that long reads are logged +too_long_threshold = box.cfg.too_long_threshold +--- +... +box.cfg{too_long_threshold = 0.01} +--- +... +errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", true) +--- +- ok +... +#s:select(5, {iterator = 'LE'}) == 5 +--- +- true +... +errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", false); +--- +- ok +... +test_run:cmd("push filter 'lsn=[0-9]+' to 'lsn=<lsn>'") +--- +- true +... +test_run:grep_log('default', 'select.* took too long') +--- +- select([5], LE) => REPLACE([5, "test str5"], lsn=<lsn>) took too long +... +test_run:cmd("clear filter") +--- +- true +... +box.cfg{too_long_threshold = too_long_threshold} +--- +... s:drop() --- ... diff --git a/test/vinyl/errinj.test.lua b/test/vinyl/errinj.test.lua index 5def06a0ec96ada67406a3dd835b27af7a937109..98d31182013e8e7c864576eec8a933294b6262b1 100644 --- a/test/vinyl/errinj.test.lua +++ b/test/vinyl/errinj.test.lua @@ -95,6 +95,18 @@ fiber.sleep(0.1) errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", false); errinj.set("ERRINJ_VY_READ_PAGE", false); s:select() + +-- gh-2871: check that long reads are logged +too_long_threshold = box.cfg.too_long_threshold +box.cfg{too_long_threshold = 0.01} +errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", true) +#s:select(5, {iterator = 'LE'}) == 5 +errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", false); +test_run:cmd("push filter 'lsn=[0-9]+' to 'lsn=<lsn>'") +test_run:grep_log('default', 'select.* took too long') +test_run:cmd("clear filter") +box.cfg{too_long_threshold = too_long_threshold} + s:drop() s = box.schema.space.create('test', {engine='vinyl'});