From: Vladimir Davydov <vdavydov.dev@gmail.com> To: Georgy Kirichenko <georgy@tarantool.org> Cc: tarantool-patches@freelists.org Subject: Re: [tarantool-patches] [PATCH v3 05/14] txn: get rid of autocommit from a txn structure Date: Thu, 13 Jun 2019 17:11:02 +0300 [thread overview] Message-ID: <20190613141102.dw4odqbse6cwawc4@esperanza> (raw) In-Reply-To: <e6181c23019464896f03515ac7efdd63375d2d09.1560112747.git.georgy@tarantool.org> On Sun, Jun 09, 2019 at 11:44:34PM +0300, Georgy Kirichenko wrote: > Move transaction auto start and auto commit behavior to the box level. > From now a transaction won't start and commit automatically without > txn_begin/txn_commit invocations. This is a part of a bigger transaction > refactoring in order to implement detachable transactions and a parallel > applier. TBO I don't understand why you need to move autocommit logic out of txn. The applier code already calls txn_begin/txn_commit explicitly and AFAIU this is the only place you need to care about. The code looks less readable and more bulky after this change IMHO. Let's discuss f2f. See a few comments inline. > > Prerequisites: #1254 > --- > src/box/applier.cc | 35 +++++++++++++--- > src/box/box.cc | 94 +++++++++++++++++++++++++++++++++--------- > src/box/index.cc | 10 ++--- > src/box/memtx_engine.c | 10 ++++- > src/box/memtx_space.c | 8 ++-- > src/box/sql.c | 2 +- > src/box/txn.c | 46 +++++++-------------- > src/box/txn.h | 16 +++---- > src/box/vinyl.c | 12 ++---- > src/box/vy_scheduler.c | 6 +-- > 10 files changed, 148 insertions(+), 91 deletions(-) > > diff --git a/src/box/applier.cc b/src/box/applier.cc > index 373e1feb9..e3203a4c8 100644 > --- a/src/box/applier.cc > +++ b/src/box/applier.cc > @@ -172,11 +172,26 @@ applier_writer_f(va_list ap) > static int > apply_initial_join_row(struct xrow_header *row) > { > + struct txn *txn = txn_begin(); > + if (txn == NULL) > + return -1; > struct request request; > xrow_decode_dml(row, &request, dml_request_key_map(row->type)); > - struct space *space = space_cache_find_xc(request.space_id); > + struct space *space = space_cache_find(request.space_id); > + if (space == NULL) > + goto rollback; > /* no access checks here - applier always works with admin privs */ > - return space_apply_initial_join_row(space, &request); > + if (space_apply_initial_join_row(space, &request)) > + goto rollback; > + int rc; > + rc = txn_commit(txn); > + if (rc < 0) > + return -1; > + fiber_gc(); fiber_gc() must be called after txn_commit() while txn_rollback() calls it by itself. This is a mess. As a matter of fact, I don't understand why we need to call this function at all now, when we have txn->region which is used to allocate all txn stuff. AFAIU fiber->gc is only used for allocating temporary objects, in which case the caller is supposed to clean up by himself (using region_truncate). That said, I don't think we need to call fiber_gc() after txn_commit() at all. There's one exception though - it's vdbe_add_new_autoinc_id, which stores autogenerated ids on fiber->gc and doesn't delete them until the corresponding SQL request is complete (this is why all this mess with fiber_gc() started AFAIR). However, I think we could and should use a mempool for such allocations. I think that before pushing this patch, we should clean up fiber_gc() usage, otherwise it's really easy to loose track where we must and where we mustn't call fiber_gc() now. Actually, I think we should do that irrespective of whether we commit this patch or not. > @@ -403,8 +418,16 @@ applier_join(struct applier *applier) > applier->last_row_time = ev_monotonic_now(loop()); > if (iproto_type_is_dml(row.type)) { > vclock_follow_xrow(&replicaset.vclock, &row); > - if (apply_row(&row) != 0) > + struct txn *txn = txn_begin(); > + if (txn == NULL) > + diag_raise(); > + if (apply_row(&row) != 0) { > + txn_rollback(); > + diag_raise(); > + } > + if (txn_commit(txn) != 0) > diag_raise(); > + fiber_gc(); I'd wrap this into a helper function (apply_final_join_row). > diff --git a/src/box/box.cc b/src/box/box.cc > index 57419ee01..7f23716e5 100644 > --- a/src/box/box.cc > +++ b/src/box/box.cc > @@ -169,34 +169,62 @@ int > box_process_rw(struct request *request, struct space *space, > struct tuple **result) > { > + struct tuple *tuple = NULL; > + struct txn *txn = in_txn(); > + bool is_autocommit = txn == NULL; > + if (is_autocommit && (txn = txn_begin()) == NULL) > + return -1; > assert(iproto_type_is_dml(request->type)); > rmean_collect(rmean_box, request->type, 1); > if (access_check_space(space, PRIV_W) != 0) > - return -1; > - struct txn *txn = txn_begin_stmt(space); > - if (txn == NULL) > - return -1; > - struct tuple *tuple; > + goto fail; > + if (txn_begin_stmt(txn, space) == NULL) > + goto fail; > if (space_execute_dml(space, txn, request, &tuple) != 0) { > - txn_rollback_stmt(); > - return -1; > + txn_rollback_stmt(txn); > + goto fail; > + } > + if (result != NULL) > + *result = tuple; > + > + if (result == NULL || tuple == NULL) { > + if (txn_commit_stmt(txn, request) != 0) > + goto fail; > + if (is_autocommit) { > + if (txn_commit(txn) != 0) > + return -1; > + fiber_gc(); > + } > + return 0; > } > - if (result == NULL) > - return txn_commit_stmt(txn, request); > - *result = tuple; > - if (tuple == NULL) > - return txn_commit_stmt(txn, request); > /* > * Pin the tuple locally before the commit, > * otherwise it may go away during yield in > * when WAL is written in autocommit mode. > */ > tuple_ref(tuple); > - int rc = txn_commit_stmt(txn, request); > - if (rc == 0) > - tuple_bless(tuple); > + > + if (txn_commit_stmt(txn, request)) { > + /* Unref tuple and rollback if autocommit. */ > + tuple_unref(tuple); > + goto fail; > + } > + if (is_autocommit) { > + if (txn_commit(txn) != 0) { > + /* Unref tuple and exit. */ > + tuple_unref(tuple); > + return -1; > + } > + fiber_gc(); > + } > + tuple_bless(tuple); This looks like a lot of copy-n-paste. Please think on how to get rid of code duplication. > @@ -299,10 +327,20 @@ apply_wal_row(struct xstream *stream, struct xrow_header *row) > xrow_decode_dml_xc(row, &request, dml_request_key_map(row->type)); > if (request.type != IPROTO_NOP) { > struct space *space = space_cache_find_xc(request.space_id); > + struct txn *txn = txn_begin(); > + if (txn == NULL) { > + say_error("error applying row: %s", request_str(&request)); > + diag_raise(); > + } Why? box_process_rw can handle autocommit statements. > if (box_process_rw(&request, space, NULL) != 0) { > say_error("error applying row: %s", request_str(&request)); > + txn_rollback(); > diag_raise(); > } > + if (txn_commit(txn) != 0) { > + diag_raise(); > + } > + fiber_gc(); > } > struct wal_stream *xstream = > container_of(stream, struct wal_stream, base); > @@ -1313,9 +1351,17 @@ box_sequence_reset(uint32_t seq_id) > static inline void > box_register_replica(uint32_t id, const struct tt_uuid *uuid) > { > + struct txn *txn = txn_begin(); > + if (txn == NULL) > + diag_raise(); > if (boxk(IPROTO_INSERT, BOX_CLUSTER_ID, "[%u%s]", Again, boxk call box_process_rw, which handles autocommit. No need to call txn_begin/txn_commit here explicitly. > @@ -1636,10 +1682,18 @@ box_set_replicaset_uuid(const struct tt_uuid *replicaset_uuid) > uu = *replicaset_uuid; > else > tt_uuid_create(&uu); > + struct txn *txn = txn_begin(); > + if (txn == NULL) > + diag_raise(); > /* Save replica set UUID in _schema */ > if (boxk(IPROTO_INSERT, BOX_SCHEMA_ID, "[%s%s]", "cluster", Same here. > diff --git a/src/box/index.cc b/src/box/index.cc > index 4a444e5d0..7f26c9bc2 100644 > --- a/src/box/index.cc > +++ b/src/box/index.cc > @@ -274,7 +274,7 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key, > if (txn_begin_ro_stmt(space, &txn) != 0) > return -1; > if (index_min(index, key, part_count, result) != 0) { > - txn_rollback_stmt(); > + txn_rollback_stmt(txn); In general I like that txn_rollback_stmt and txn_rollback now take txn. This makes the API more symmetric. Probably, worth doing in a separate patch, even if we realize we don't need this one. As a matter of fact, doing this in a separate patch would make review easier. I'd appreciate if you could split this patch. > diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c > index f4312484a..149215b87 100644 > --- a/src/box/memtx_engine.c > +++ b/src/box/memtx_engine.c > @@ -272,16 +272,22 @@ memtx_engine_recover_snapshot_row(struct memtx_engine *memtx, > diag_set(ClientError, ER_CROSS_ENGINE_TRANSACTION); > return -1; > } > + struct txn *txn = txn_begin(); > + if (txn == NULL) > + return -1; > /* no access checks here - applier always works with admin privs */ > - if (space_apply_initial_join_row(space, &request) != 0) > + if (space_apply_initial_join_row(space, &request) != 0) { > + txn_rollback(); > return -1; > + } > + int rc = txn_commit(txn); This is the second place where you surround apply_initial_join_row with txn_begin/txn_commit. May be, worth doing it in the callback itself? Note, we only need this in case of memtx - vinyl doesn't create a txn object for initial recover or join. > diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c > index 1d209033c..1e630783b 100644 > --- a/src/box/memtx_space.c > +++ b/src/box/memtx_space.c > @@ -310,10 +310,10 @@ memtx_space_apply_initial_join_row(struct space *space, struct request *request) > return -1; > } > request->header->replica_id = 0; > - struct txn *txn = txn_begin_stmt(space); > - if (txn == NULL) > + struct txn *txn = in_txn(); > + struct txn_stmt *stmt = txn_begin_stmt(txn, space); > + if (stmt == NULL) > return -1; > - struct txn_stmt *stmt = txn_current_stmt(txn); AFAICS this is the only place where you use txn_stmt returned by txn_begin_stmt() - in other places you simply check if it's NULL (which indicates an error). Why did you decide to make txn_begin_stmt() return txn_stmt rather than an error code? The API looks lopsided now: txn_begin() => txn txn_begin_stmt(txn, request) => txn_stmt txn_commit_stmt(txn) => int txn_commit(txn) => int Let's please make txn_begin_stmt return int and use txn_current_stmt here to get txn_stmt, as we used to. This shouldn't affect performance while the code would look neater this way. > diff --git a/src/box/txn.c b/src/box/txn.c > index 1d8271e51..21f34e526 100644 > --- a/src/box/txn.c > +++ b/src/box/txn.c > @@ -441,14 +428,11 @@ fail: > } > > void > -txn_rollback_stmt() > +txn_rollback_stmt(struct txn *txn) > { > - struct txn *txn = in_txn(); > if (txn == NULL || txn->in_sub_stmt == 0) > return; Hmm, how's that even possible now?
next prev parent reply other threads:[~2019-06-13 14:11 UTC|newest] Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-06-09 20:44 [tarantool-patches] [PATCH v3 00/14] Parallel applier Georgy Kirichenko 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 01/14] txn: Fire a trigger after a transaction finalization Georgy Kirichenko 2019-06-09 21:59 ` [tarantool-patches] " Konstantin Osipov 2019-06-11 11:42 ` [tarantool-patches] " Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 02/14] ddl: synchronize privileges cache with actual data state Georgy Kirichenko 2019-06-11 13:13 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 03/14] txn: transaction memory allocation Georgy Kirichenko 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 04/14] ddl: place alter structures onto a txn memory region Georgy Kirichenko 2019-06-11 14:14 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 05/14] txn: get rid of autocommit from a txn structure Georgy Kirichenko 2019-06-13 14:11 ` Vladimir Davydov [this message] 2019-06-16 16:20 ` [tarantool-patches] " Konstantin Osipov 2019-06-16 16:14 ` Konstantin Osipov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 06/14] txn: get rid of fiber_gc from txn_rollback Georgy Kirichenko 2019-06-13 14:12 ` Vladimir Davydov 2019-06-13 19:28 ` Георгий Кириченко 2019-06-14 9:21 ` Vladimir Davydov 2019-06-16 16:38 ` [tarantool-patches] " Konstantin Osipov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 07/14] wal: remove fiber from a journal_entry structure Georgy Kirichenko 2019-06-13 14:17 ` Vladimir Davydov 2019-06-13 19:33 ` Георгий Кириченко 2019-06-14 8:05 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 08/14] wal: enable asyncronous wal writes Georgy Kirichenko 2019-06-13 14:21 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 09/14] wal: a dedicated wal scheduling fiber Georgy Kirichenko 2019-06-13 14:24 ` Vladimir Davydov 2019-06-13 19:36 ` Георгий Кириченко 2019-06-14 9:20 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 10/14] core: latch_unlock_external routine Georgy Kirichenko 2019-06-13 14:27 ` Vladimir Davydov 2019-06-13 19:38 ` Георгий Кириченко 2019-06-14 8:10 ` Vladimir Davydov 2019-06-14 9:18 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 11/14] txn: introduce asynchronous txn commit Georgy Kirichenko 2019-06-13 14:34 ` Vladimir Davydov 2019-06-13 19:45 ` Георгий Кириченко 2019-06-14 7:58 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 12/14] txn: handle fiber stop event at transaction level Georgy Kirichenko 2019-06-13 14:36 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 13/14] applier: apply transaction in parallel Georgy Kirichenko 2019-06-13 15:17 ` Vladimir Davydov 2019-06-09 20:44 ` [tarantool-patches] [PATCH v3 14/14] test: fix flaky test Georgy Kirichenko
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=20190613141102.dw4odqbse6cwawc4@esperanza \ --to=vdavydov.dev@gmail.com \ --cc=georgy@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH v3 05/14] txn: get rid of autocommit from a txn structure' \ /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