From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 35AB36EC40; Sun, 8 Aug 2021 14:43:16 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 35AB36EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1628422996; bh=gPJ9Z6wvUhfLLJdQ7Cq3en4AIbpKabnaA/zqiJgyFRM=; h=To:References:Date:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=oCJCPvXia+8+41phvEDovE3zypptIvtF+GiR9Pk7uuYJhEMZwPJXP0aoYKD+VZZ9u 2FhiFoU2E1LmUrkCPEw6ba4Tlq7NrlKV1N/dMddzf0UZ+NSxPIZ0aHMOnU5UvrJ7pj cBRDOUZx2s+mH+MU/LpnvY/jeEGGaQzVT7gS0dRg= Received: from smtp41.i.mail.ru (smtp41.i.mail.ru [94.100.177.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 760346EC40 for ; Sun, 8 Aug 2021 14:43:15 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 760346EC40 Received: by smtp41.i.mail.ru with esmtpa (envelope-from ) id 1mChD0-0006Bi-OB; Sun, 08 Aug 2021 14:43:15 +0300 To: Cyrill Gorcunov References: <20210804190752.488147-1-gorcunov@gmail.com> <20210804190752.488147-4-gorcunov@gmail.com> Message-ID: <7e881b83-478c-6bc0-615d-ade811da8471@tarantool.org> Date: Sun, 8 Aug 2021 14:43:14 +0300 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD94BB7C0677F3ED9D05EB08EAFC9298EA6182A05F53808504000733E302602957D7B18E6E024A87B5AB9599C52F1AACE14B6238D94B64F67CA X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE745229D52CF30560CEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006374C1E21D5B12C874B8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D876C9BE86ECBDA14BAAF959E5CE062683117882F4460429724CE54428C33FAD305F5C1EE8F4F765FC2EE5AD8F952D28FBA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F446042972877693876707352033AC447995A7AD186FD1C55BDD38FC3FD2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EED76C6ED7039589DE68E75A379BAF682BD8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE362B3BD3CC35DA5886136E347CC761E07C4224003CC836476EA7A3FFF5B025636E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F7900637BBEA499411984DA1EFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-C1DE0DAB: 0D63561A33F958A5576D36796B538617F43756A1BF2CCD481CA5294071D3BA3BD59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA75AF0B556A5A327A45410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3435BBF0AC4E3A921CFA0B9EC4C7E83D7961C7A2C40AFD739F07DBD640B08D64DEBC12DDFFFE4AD3751D7E09C32AA3244C8D0957E7762C0914EB17A3E349D42B6D795D98D676DD64D0FACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojMTMPlNJj3Sg7KlpsF+mnHQ== X-Mailru-Sender: 6C3E74F07C41AE94D32402E5012278FA6CA8767E1AF5801EB5E1BBCBFC23F6A711CF74B46748A2FC07784C02288277CA03E0582D3806FB6A5317862B1921BA260ED6CFD6382C13A6112434F685709FCF0DA7A0AF5A3A8387 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v10 3/4] limbo: filter incoming synchro requests X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Vladislav Shpilevoy via Tarantool-patches Reply-To: Vladislav Shpilevoy Cc: tml Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Hi! Thanks for working on this! >>> diff --git a/src/box/applier.cc b/src/box/applier.cc >>> index 9db286ae2..f64b6fa35 100644 >>> --- a/src/box/applier.cc >>> +++ b/src/box/applier.cc >>> @@ -514,6 +515,11 @@ applier_fetch_snapshot(struct applier *applier) >>> struct ev_io *coio = &applier->io; >>> struct xrow_header row; >>> >>> + txn_limbo_filter_disable(&txn_limbo); >>> + auto filter_guard = make_scoped_guard([&]{ >>> + txn_limbo_filter_enable(&txn_limbo); >>> + }); >> >> 3. Why do you need to enable/disabled the filter here? Shouldn't snapshot >> contain only valid data? Moreover, AFAIU it can't contain any limbo >> rows at all. The limbo snapshot is sent separately, but the data flow >> does not have anything except pure data. The same for the >> join. > > The idea is that snapshot/recovery has valid data which forms the initial > limbo state versus which we will be apply filtering. You didn't answer the question really. Why do you need the filtering here if all the data is correct anyway? Will it all work if I just drop this filter disable from here? >> And how is it related to applier_register below? It does not download >> any data at all, does it? > > After register stage is complete we catch up with lates not yet downloaded > data (final join stage) where we still assume that the data received is > valid and do not verify it. Register just makes the master give you a unique ID. It does not send any data like joins do, AFAIR. Does it work if you drop the filter disable from here? > Actually this is a good question. I've to recheck this moment because in > previous series when I ran join/recovery with filtering enabled sometime > I've an issues where filter didnt pass. Gimme some time, maybe we will > all this and manage to keep filtering all the time. > >>> + >>> +/** >>> + * Common chain for any incoming packet. >>> + */ >>> +static int >>> +filter_in(struct txn_limbo *limbo, const struct synchro_request *req) >>> +{ >>> + (void)limbo; >> >> 6. So you have the filtering enabled dynamically in the limbo, but >> you do not use the limbo here? Why? Maybe at least add an assertion >> that the filter is enabled? > > All chains are having same interface it is just happen that for common > filter I don't need to use limbo. I could add some operations here > but not sure if it worth it. As far as I see leave unused args is > pretty fine in our code base. You didn't answer the second question: Maybe at least add an assertion that the filter is enabled? >>> +/** >>> + * Filter CONFIRM and ROLLBACK packets. >>> + */ >>> +static int >>> +filter_confirm_rollback(struct txn_limbo *limbo, >>> + const struct synchro_request *req) >>> +{ >>> + /* >>> + * When limbo is empty we have nothing to >>> + * confirm/commit and if this request comes >>> + * in it means the split brain has happened. >>> + */ >>> + if (!txn_limbo_is_empty(limbo)) >>> + return 0; >> >> 9. What if rollback is for LSN > limbo's last LSN? It >> also means nothing to do. The same for confirm LSN < limbo's >> first LSN. > > static void > txn_limbo_read_rollback(struct txn_limbo *limbo, int64_t lsn) > { > --> assert(limbo->owner_id != REPLICA_ID_NIL || txn_limbo_is_empty(limbo)); > > txn_limbo_read_confirm(struct txn_limbo *limbo, int64_t lsn) > { > --> assert(limbo->owner_id != REPLICA_ID_NIL || txn_limbo_is_empty(limbo)); > > Currently we're allowed to process empty limbo if only owner is not nil, > I think I should add this case here. My question is not about the owner ID. I asked what if rollback/confirm try to cover a range not present in the limbo while it is not empty. If it is not empty, it has an owner obviously. But it does not matter. What if it has an owner, has transactions, but you got ROLLBACK/CONFIRM for data out of the LSN range present in the limbo? >>> + /* >>> + * Some entries are present in the limbo, >>> + * we need to make sure the @a promote_lsn >>> + * lays inside limbo [first; last] range. >>> + * So that the promote request has some >>> + * queued data to process, otherwise it >>> + * means the request comes from split >>> + * brained node. >>> + */ >>> + struct txn_limbo_entry *first, *last; >>> + >>> + first = txn_limbo_first_entry(limbo); >>> + last = txn_limbo_last_entry(limbo); >>> + >>> + if (first->lsn < promote_lsn || >>> + last->lsn > promote_lsn) { >> >> 11. This seems to be broken. In the comment you said the >> error is when >> >> promote < first or promote > last >> >> And here in the condition you return an error when >> >> promote > first or promote < last >> >> Why? > > Good catch, typo. Actually I've updated this hunk locally > but didn't pushed out. We need "first <= promote <= last" Is it covered with a test? >>> +static int (*filter_req[FILTER_MAX]) >>> +(struct txn_limbo *limbo, const struct synchro_request *req) = { >>> + [FILTER_IN] = filter_in, >>> + [FILTER_CONFIRM] = filter_confirm_rollback, >>> + [FILTER_ROLLBACK] = filter_confirm_rollback, >>> + [FILTER_PROMOTE] = filter_promote_demote, >>> + [FILTER_DEMOTE] = filter_promote_demote, >> >> 12. What is this? Wouldn't it be much much much simpler to just >> call filter_in() always + make a switch case for the request type + >> call the needed functions? >> >> What is worse, you already have the switch-case anyway, but you >> also added some strange loop, masks, and virtual functions ... . >> I don't think I could make it more complex even if I wanted to, >> sorry. Why so complicated? > > It might be look easier but won't allow to extend filtering in future > without rewritting too much. I propose to think about that when we add more packet types. Also, in your code you will need to extend both switch-case and your masks. While if we had only the switch-case, you would only need to update the switch-case. So it means less work. 'Switch-case' vs 'switch-case + virtual functions and the loop'. > I'm pretty sure this number of packet types > is not finished and we will have more. Using bitmap routing you can easily > hook in any call sequence you need while using explicit if\elses or direct > calls via case-by-request-type won't allow to make it so. So no, this is > not complicated at all but rather close to real packet filtering code. You literally filter 4 packet types. Please, do not overcomplicate it. It is not kernel, not some network filter for all kinds of protocols. It is just 4 packet types. Which you **already** walk in switch-case + call the virtual functions in a loop. While I propose to keep only the switch-case. Even its extension will look simpler than what you have now. Because you will also need to patch the switch-case. Just compare: filters = [ ... ] switch { case ...: case ...: } while (...) { ... } vs switch { case ...: case ...: } You have the first version, and will need to update the masks, the switch-case and still have the loop with a fullscan. In the second version you only would have a switch-case. Doesn't it look simpler? > Anyway, which form would you prefer? > > txn_limbo_filter_locked() { > int rc = filter_in(); > if (rc != 0) > return -1; > > swicth (req->type) { > case IPROTO_CONFIRM: > case IPROTO_ROLLBACK: > rc = filter_confirm_rollback(); > break; > ... > } > > return rc; > } > > Kind of this? Yes! It is much simpler and still easy to extend. Please, just try and you will see how much simpler it is.