From: Nikita Pettik <korablev@tarantool.org> To: tarantool-patches@dev.tarantool.org Cc: v.shpilevoy@tarantool.org Subject: [Tarantool-patches] [PATCH 2/2] vinyl: skip invalid upserts during squash Date: Tue, 14 Apr 2020 00:55:45 +0300 [thread overview] Message-ID: <670c3876e58a7cfa14d45db1dc074a10dd034759.1586808463.git.korablev@tarantool.org> (raw) In-Reply-To: <cover.1586808463.git.korablev@tarantool.org> In-Reply-To: <cover.1586808463.git.korablev@tarantool.org> Instead of aborting merge sequence of upserts let's log appeared errors and skip upserts which can't be applied. It makes sense taking into consideration previous commit: now upsert statements which can't be applied may appear in mems/runs (previously squash operation might fail only due to OOM). As a result, if we didn't ignore invalid upserts, dump or compaction processes would not be able to finish (owing to inability to squash upserts). Closes #1622 --- src/box/vy_history.c | 20 +++- src/box/vy_lsm.c | 13 +- src/box/vy_tx.c | 29 +++-- src/box/vy_write_iterator.c | 34 ++++-- .../vinyl/gh-1622-skip-invalid-upserts.result | 113 +++++++++++++++++- .../gh-1622-skip-invalid-upserts.test.lua | 41 ++++++- 6 files changed, 220 insertions(+), 30 deletions(-) diff --git a/src/box/vy_history.c b/src/box/vy_history.c index 0f3b71195..55eb3c669 100644 --- a/src/box/vy_history.c +++ b/src/box/vy_history.c @@ -102,12 +102,20 @@ vy_history_apply(struct vy_history *history, struct key_def *cmp_def, while (node != NULL) { struct tuple *stmt = vy_apply_upsert(node->stmt, curr_stmt, cmp_def, format, true); - ++*upserts_applied; - if (curr_stmt != NULL) - tuple_unref(curr_stmt); - if (stmt == NULL) - return -1; - curr_stmt = stmt; + if (stmt == NULL) { + /* + * In case statement hasn't been applied, + * simply skip it ignoring errors (otherwise + * error will appear during tuple read). + */ + assert(diag_last_error(diag_get()) != NULL); + diag_clear(diag_get()); + } else { + ++*upserts_applied; + if (curr_stmt != NULL) + tuple_unref(curr_stmt); + curr_stmt = stmt; + } node = rlist_prev_entry_safe(node, &history->stmts, link); } *ret = curr_stmt; diff --git a/src/box/vy_lsm.c b/src/box/vy_lsm.c index 04c9926a8..3d630fc01 100644 --- a/src/box/vy_lsm.c +++ b/src/box/vy_lsm.c @@ -984,13 +984,20 @@ vy_lsm_commit_upsert(struct vy_lsm *lsm, struct vy_mem *mem, struct tuple *upserted = vy_apply_upsert(stmt, older, lsm->cmp_def, lsm->mem_format, false); - lsm->stat.upsert.applied++; - if (upserted == NULL) { - /* OOM */ + /* + * OOM or upserted tuple does not fulfill + * space format. Hence, upsert can't be + * transformed into replace. Log error + * and exit. + */ + struct error *e = diag_last_error(diag_get()); + assert(e != NULL); + error_log(e); diag_clear(diag_get()); return; } + lsm->stat.upsert.applied++; int64_t upserted_lsn = vy_stmt_lsn(upserted); if (upserted_lsn != lsn) { /** diff --git a/src/box/vy_tx.c b/src/box/vy_tx.c index 5029bd8a1..060a7f6a9 100644 --- a/src/box/vy_tx.c +++ b/src/box/vy_tx.c @@ -515,11 +515,15 @@ vy_tx_write(struct vy_lsm *lsm, struct vy_mem *mem, region_stmt); tuple_unref(applied); return rc; + } else { + /* + * Ignore a memory error, because it is + * not critical to apply the optimization. + * Clear diag: otherwise error is set but + * function may return success return code. + */ + diag_clear(diag_get()); } - /* - * Ignore a memory error, because it is - * not critical to apply the optimization. - */ } } else { /* Invalidate cache element. */ @@ -1047,12 +1051,17 @@ vy_tx_set(struct vy_tx *tx, struct vy_lsm *lsm, struct tuple *stmt) applied = vy_apply_upsert(stmt, old->stmt, lsm->cmp_def, lsm->mem_format, true); - lsm->stat.upsert.applied++; - if (applied == NULL) - return -1; - stmt = applied; - assert(vy_stmt_type(stmt) != 0); - lsm->stat.upsert.squashed++; + if (applied == NULL) { + struct error *e = diag_last_error(diag_get()); + assert(e != NULL); + error_log(e); + diag_clear(diag_get()); + } else { + lsm->stat.upsert.applied++; + stmt = applied; + assert(vy_stmt_type(stmt) != 0); + lsm->stat.upsert.squashed++; + } } /* Allocate a MVCC container. */ diff --git a/src/box/vy_write_iterator.c b/src/box/vy_write_iterator.c index 7a6a20627..4b5b3e673 100644 --- a/src/box/vy_write_iterator.c +++ b/src/box/vy_write_iterator.c @@ -850,10 +850,22 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint, vy_stmt_type(hint) != IPROTO_UPSERT); struct tuple *applied = vy_apply_upsert(h->tuple, hint, stream->cmp_def, stream->format, false); - if (applied == NULL) - return -1; - vy_stmt_unref_if_possible(h->tuple); - h->tuple = applied; + if (applied == NULL) { + /* + * Current upsert can't be applied. + * Let's skip it and log error. + */ + struct error *e = diag_last_error(diag_get()); + assert(e != NULL); + say_info("Upsert %s is not applied due to the error: %s", + vy_stmt_str(h->tuple), e->errmsg); + diag_clear(diag_get()); + vy_stmt_unref_if_possible(h->tuple); + h->tuple = hint; + } else { + vy_stmt_unref_if_possible(h->tuple); + h->tuple = applied; + } } /* Squash the rest of UPSERTs. */ struct vy_write_history *result = h; @@ -864,10 +876,16 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint, assert(result->tuple != NULL); struct tuple *applied = vy_apply_upsert(h->tuple, result->tuple, stream->cmp_def, stream->format, false); - if (applied == NULL) - return -1; - vy_stmt_unref_if_possible(result->tuple); - result->tuple = applied; + if (applied == NULL) { + struct error *e = diag_last_error(diag_get()); + assert(e != NULL); + say_info("Upsert %s is not applied due to the error: %s", + vy_stmt_str(h->tuple), e->errmsg); + diag_clear(diag_get()); + } else { + vy_stmt_unref_if_possible(result->tuple); + result->tuple = applied; + } vy_stmt_unref_if_possible(h->tuple); /* * Don't bother freeing 'h' since it's diff --git a/test/vinyl/gh-1622-skip-invalid-upserts.result b/test/vinyl/gh-1622-skip-invalid-upserts.result index 437ff3c51..b59ed53dc 100644 --- a/test/vinyl/gh-1622-skip-invalid-upserts.result +++ b/test/vinyl/gh-1622-skip-invalid-upserts.result @@ -14,11 +14,120 @@ s:replace{1, 1} s:upsert({1, 1}, {{'=', 3, 5}}) | --- | ... --- Invalid upsert still appears during read. +-- During read the incorrect upsert is ignored. -- s:select{} | --- - | - error: Tuple field count 3 does not match space field count 2 + | - - [1, 1] + | ... + +-- Try to set incorrect field_count in a transaction. +-- +box.begin() + | --- + | ... +s:replace{2, 2} + | --- + | - [2, 2] + | ... +s:upsert({2, 2}, {{'=', 3, 2}}) + | --- + | ... +s:select{} + | --- + | - - [1, 1] + | - [2, 2] + | ... +box.commit() + | --- + | ... +s:select{} + | --- + | - - [1, 1] + | - [2, 2] + | ... + +-- Read incorrect upsert from a run: it should be ignored. +-- +box.snapshot() + | --- + | - ok + | ... +s:select{} + | --- + | - - [1, 1] + | - [2, 2] + | ... +s:upsert({2, 2}, {{'=', 3, 20}}) + | --- + | ... +box.snapshot() + | --- + | - ok + | ... +s:select{} + | --- + | - - [1, 1] + | - [2, 2] + | ... + +-- Execute replace/delete after invalid upsert. +-- +box.snapshot() + | --- + | - ok + | ... +s:upsert({2, 2}, {{'=', 3, 30}}) + | --- + | ... +s:replace{2, 3} + | --- + | - [2, 3] + | ... +s:select{} + | --- + | - - [1, 1] + | - [2, 3] + | ... + +s:upsert({1, 1}, {{'=', 3, 30}}) + | --- + | ... +s:delete{1} + | --- + | ... +s:select{} + | --- + | - - [2, 3] + | ... + +-- Invalid upsert in a sequence of upserts is skipped meanwhile +-- the rest are applied. +-- +box.snapshot() + | --- + | - ok + | ... +s:upsert({2, 2}, {{'+', 2, 5}}) + | --- + | ... +s:upsert({2, 2}, {{'=', 3, 40}}) + | --- + | ... +s:upsert({2, 2}, {{'+', 2, 5}}) + | --- + | ... +s:select{} + | --- + | - - [2, 13] + | ... +box.snapshot() + | --- + | - ok + | ... +s:select{} + | --- + | - - [2, 13] | ... s:drop() diff --git a/test/vinyl/gh-1622-skip-invalid-upserts.test.lua b/test/vinyl/gh-1622-skip-invalid-upserts.test.lua index 952d2bcde..eb93393be 100644 --- a/test/vinyl/gh-1622-skip-invalid-upserts.test.lua +++ b/test/vinyl/gh-1622-skip-invalid-upserts.test.lua @@ -4,8 +4,47 @@ s:replace{1, 1} -- Error is logged, upsert is not applied. -- s:upsert({1, 1}, {{'=', 3, 5}}) --- Invalid upsert still appears during read. +-- During read the incorrect upsert is ignored. -- s:select{} +-- Try to set incorrect field_count in a transaction. +-- +box.begin() +s:replace{2, 2} +s:upsert({2, 2}, {{'=', 3, 2}}) +s:select{} +box.commit() +s:select{} + +-- Read incorrect upsert from a run: it should be ignored. +-- +box.snapshot() +s:select{} +s:upsert({2, 2}, {{'=', 3, 20}}) +box.snapshot() +s:select{} + +-- Execute replace/delete after invalid upsert. +-- +box.snapshot() +s:upsert({2, 2}, {{'=', 3, 30}}) +s:replace{2, 3} +s:select{} + +s:upsert({1, 1}, {{'=', 3, 30}}) +s:delete{1} +s:select{} + +-- Invalid upsert in a sequence of upserts is skipped meanwhile +-- the rest are applied. +-- +box.snapshot() +s:upsert({2, 2}, {{'+', 2, 5}}) +s:upsert({2, 2}, {{'=', 3, 40}}) +s:upsert({2, 2}, {{'+', 2, 5}}) +s:select{} +box.snapshot() +s:select{} + s:drop() \ No newline at end of file -- 2.17.1
next prev parent reply other threads:[~2020-04-13 21:55 UTC|newest] Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-04-13 21:55 [Tarantool-patches] [PATCH 0/2] Validate result of upserts squash & skip invalid upserts which can't be applied Nikita Pettik 2020-04-13 21:55 ` [Tarantool-patches] [PATCH 1/2] vinyl: validate resulting tuple after upsert is applied Nikita Pettik 2020-06-22 19:28 ` Aleksandr Lyapunov 2020-04-13 21:55 ` Nikita Pettik [this message] 2020-04-13 22:12 ` [Tarantool-patches] [PATCH 2/2] vinyl: skip invalid upserts during squash Konstantin Osipov 2020-05-14 2:11 ` Nikita Pettik 2020-05-14 6:56 ` Konstantin Osipov 2020-05-19 19:10 ` Nikita Pettik 2020-05-19 19:39 ` Konstantin Osipov 2020-05-21 2:51 ` Nikita Pettik 2020-05-21 8:36 ` Konstantin Osipov 2020-05-01 0:31 ` Vladislav Shpilevoy 2020-05-14 2:21 ` Nikita Pettik 2020-05-14 21:32 ` Vladislav Shpilevoy 2020-05-19 18:18 ` Nikita Pettik 2020-05-20 22:13 ` Vladislav Shpilevoy 2020-05-26 21:33 ` Vladislav Shpilevoy 2020-05-27 20:05 ` Nikita Pettik 2020-05-29 21:47 ` Vladislav Shpilevoy 2020-06-01 19:24 ` Nikita Pettik 2020-05-20 22:13 ` [Tarantool-patches] [PATCH 0/2] Validate result of upserts squash & skip invalid upserts which can't be applied Vladislav Shpilevoy 2020-05-22 2:42 ` Nikita Pettik 2020-05-26 21:33 ` Vladislav Shpilevoy 2020-05-27 20:10 ` Nikita Pettik 2020-06-22 14:13 ` Aleksandr Lyapunov 2020-06-22 20:21 ` Nikita Pettik 2020-06-23 12:32 ` Aleksandr Lyapunov 2020-06-02 21:36 ` Vladislav Shpilevoy 2020-06-02 21:37 ` Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=670c3876e58a7cfa14d45db1dc074a10dd034759.1586808463.git.korablev@tarantool.org \ --to=korablev@tarantool.org \ --cc=tarantool-patches@dev.tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH 2/2] vinyl: skip invalid upserts during squash' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox