From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 989332CCBC for ; Fri, 19 Apr 2019 08:44:11 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id T0tnv1bivd9h for ; Fri, 19 Apr 2019 08:44:11 -0400 (EDT) Received: from smtp50.i.mail.ru (smtp50.i.mail.ru [94.100.177.110]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id B9C2A2CCAC for ; Fri, 19 Apr 2019 08:44:10 -0400 (EDT) From: Georgy Kirichenko Subject: [tarantool-patches] [PATCH 01/10] Introduce a txn memory region Date: Fri, 19 Apr 2019 15:43:57 +0300 Message-Id: <578b5150bc489f2839387f8b95c8068e6649d455.1555677159.git.georgy@tarantool.org> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org Cc: Georgy Kirichenko Attach a separate memory region for each txn structure in order to store all txn internal data until the transaction finished. This patch is a preparation to detach a txn from a fiber and a fiber gc storage. Prerequisites: #1254 --- src/box/errcode.h | 2 +- src/box/sql/vdbe.c | 2 +- src/box/txn.c | 71 +++++++++++++++++++++++++++++------- src/box/txn.h | 2 + test/box/misc.result | 2 +- test/engine/savepoint.result | 2 +- test/sql/savepoints.result | 6 +-- 7 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/box/errcode.h b/src/box/errcode.h index 3f8cb8e0e..a273826b3 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -166,7 +166,7 @@ struct errcode_record { /*111 */_(ER_WRONG_SPACE_OPTIONS, "Wrong space options (field %u): %s") \ /*112 */_(ER_UNSUPPORTED_INDEX_FEATURE, "Index '%s' (%s) of space '%s' (%s) does not support %s") \ /*113 */_(ER_VIEW_IS_RO, "View '%s' is read-only") \ - /*114 */_(ER_SAVEPOINT_NO_TRANSACTION, "Can not set a savepoint in absence of active transaction") \ + /*114 */_(ER_NO_TRANSACTION, "No active transaction") \ /*115 */_(ER_SYSTEM, "%s") \ /*116 */_(ER_LOADING, "Instance bootstrap hasn't finished yet") \ /*117 */_(ER_CONNECTION_TO_SELF, "Connection to self") \ diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index ed7bf8870..9fc70980c 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -3017,7 +3017,7 @@ case OP_Savepoint: { if (psql_txn == NULL) { assert(!box_txn()); - diag_set(ClientError, ER_SAVEPOINT_NO_TRANSACTION); + diag_set(ClientError, ER_NO_TRANSACTION); rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } diff --git a/src/box/txn.c b/src/box/txn.c index d51bfc67a..815199645 100644 --- a/src/box/txn.c +++ b/src/box/txn.c @@ -37,6 +37,9 @@ double too_long_threshold; +/* Txn cache. */ +static struct stailq txn_cache = {NULL, &txn_cache.first}; + static inline void fiber_set_txn(struct fiber *fiber, struct txn *txn) { @@ -44,7 +47,7 @@ fiber_set_txn(struct fiber *fiber, struct txn *txn) } static int -txn_add_redo(struct txn_stmt *stmt, struct request *request) +txn_add_redo(struct txn *txn, struct txn_stmt *stmt, struct request *request) { stmt->row = request->header; if (request->header != NULL) @@ -52,7 +55,7 @@ txn_add_redo(struct txn_stmt *stmt, struct request *request) /* Create a redo log row for Lua requests */ struct xrow_header *row; - row = region_alloc_object(&fiber()->gc, struct xrow_header); + row = region_alloc_object(&txn->region, struct xrow_header); if (row == NULL) { diag_set(OutOfMemory, sizeof(*row), "region", "struct xrow_header"); @@ -77,7 +80,7 @@ static struct txn_stmt * txn_stmt_new(struct txn *txn) { struct txn_stmt *stmt; - stmt = region_alloc_object(&fiber()->gc, struct txn_stmt); + stmt = region_alloc_object(&txn->region, struct txn_stmt); if (stmt == NULL) { diag_set(OutOfMemory, sizeof(*stmt), "region", "struct txn_stmt"); @@ -134,16 +137,50 @@ txn_rollback_to_svp(struct txn *txn, struct stailq_entry *svp) } } +/* + * Return a txn from cache or create a new one if cache is empty. + */ +inline static struct txn * +txn_new() +{ + if (!stailq_empty(&txn_cache)) + return stailq_shift_entry(&txn_cache, struct txn, list); + + /* Create a region. */ + struct region region; + region_create(®ion, &cord()->slabc); + + /* Place txn structure on the region. */ + struct txn *txn = region_alloc_object(®ion, struct txn); + if (txn == NULL) { + diag_set(OutOfMemory, sizeof(*txn), "region", "struct txn"); + return NULL; + } + assert(region_used(®ion) == sizeof(*txn)); + txn->region = region; + return txn; +} + +/* + * Free txn memory and return it to a cache. + */ +inline static void +txn_free(struct txn *txn) +{ + /* Truncate region up to struct txn size. */ + region_truncate(&txn->region, sizeof(struct txn)); + stailq_add(&txn_cache, &txn->list); +} + struct txn * txn_begin(bool is_autocommit) { static int64_t tsn = 0; assert(! in_txn()); - struct txn *txn = region_alloc_object(&fiber()->gc, struct txn); - if (txn == NULL) { - diag_set(OutOfMemory, sizeof(*txn), "region", "struct txn"); + struct txn *txn = txn_new(); + if (txn == NULL) return NULL; - } + /* Initialize members explicitly to save time on memset() */ stailq_create(&txn->stmts); txn->n_new_rows = 0; @@ -251,7 +288,7 @@ txn_commit_stmt(struct txn *txn, struct request *request) * stmt->space can be NULL for IRPOTO_NOP. */ if (stmt->space == NULL || !space_is_temporary(stmt->space)) { - if (txn_add_redo(stmt, request) != 0) + if (txn_add_redo(txn, stmt, request) != 0) goto fail; assert(stmt->row != NULL); if (stmt->row->replica_id == 0) { @@ -393,8 +430,8 @@ txn_commit(struct txn *txn) stailq_foreach_entry(stmt, &txn->stmts, next) txn_stmt_unref_tuples(stmt); - TRASH(txn); fiber_set_txn(fiber(), NULL); + txn_free(txn); return 0; fail: txn_rollback(); @@ -433,10 +470,10 @@ txn_rollback() stailq_foreach_entry(stmt, &txn->stmts, next) txn_stmt_unref_tuples(stmt); - TRASH(txn); /** Free volatile txn memory. */ fiber_gc(); fiber_set_txn(fiber(), NULL); + txn_free(txn); } void @@ -521,12 +558,18 @@ box_txn_rollback() void * box_txn_alloc(size_t size) { + struct txn *txn = in_txn(); + if (txn == NULL) { + /* There are no transaction yet - return an error. */ + diag_set(ClientError, ER_NO_TRANSACTION); + return NULL; + } union natural_align { void *p; double lf; long l; }; - return region_aligned_alloc(&fiber()->gc, size, + return region_aligned_alloc(&txn->region, size, alignof(union natural_align)); } @@ -535,11 +578,11 @@ box_txn_savepoint() { struct txn *txn = in_txn(); if (txn == NULL) { - diag_set(ClientError, ER_SAVEPOINT_NO_TRANSACTION); + diag_set(ClientError, ER_NO_TRANSACTION); return NULL; } struct txn_savepoint *svp = - (struct txn_savepoint *) region_alloc_object(&fiber()->gc, + (struct txn_savepoint *) region_alloc_object(&txn->region, struct txn_savepoint); if (svp == NULL) { diag_set(OutOfMemory, sizeof(*svp), @@ -558,7 +601,7 @@ box_txn_rollback_to_savepoint(box_txn_savepoint_t *svp) { struct txn *txn = in_txn(); if (txn == NULL) { - diag_set(ClientError, ER_SAVEPOINT_NO_TRANSACTION); + diag_set(ClientError, ER_NO_TRANSACTION); return -1; } struct txn_stmt *stmt = svp->stmt == NULL ? NULL : diff --git a/src/box/txn.h b/src/box/txn.h index 747b38db3..fe8a299f2 100644 --- a/src/box/txn.h +++ b/src/box/txn.h @@ -132,6 +132,8 @@ struct autoinc_id_entry { }; struct txn { + struct stailq_entry list; + struct region region; /** * A sequentially growing transaction id, assigned when * a transaction is initiated. Used to identify diff --git a/test/box/misc.result b/test/box/misc.result index a1f7a0990..d7d76d87e 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -443,7 +443,7 @@ t; 111: box.error.WRONG_SPACE_OPTIONS 112: box.error.UNSUPPORTED_INDEX_FEATURE 113: box.error.VIEW_IS_RO - 114: box.error.SAVEPOINT_NO_TRANSACTION + 114: box.error.NO_TRANSACTION 115: box.error.SYSTEM 116: box.error.LOADING 117: box.error.CONNECTION_TO_SELF diff --git a/test/engine/savepoint.result b/test/engine/savepoint.result index b3a918de0..86a2d0be2 100644 --- a/test/engine/savepoint.result +++ b/test/engine/savepoint.result @@ -14,7 +14,7 @@ s1 = nil ... s1 = box.savepoint() --- -- error: Can not set a savepoint in absence of active transaction +- error: No active transaction ... box.rollback_to_savepoint(s1) --- diff --git a/test/sql/savepoints.result b/test/sql/savepoints.result index 2f943bd9b..bb4a296fa 100644 --- a/test/sql/savepoints.result +++ b/test/sql/savepoints.result @@ -14,15 +14,15 @@ box.execute('pragma sql_default_engine=\''..engine..'\'') -- box.execute('SAVEPOINT t1;'); --- -- error: Can not set a savepoint in absence of active transaction +- error: No active transaction ... box.execute('RELEASE SAVEPOINT t1;'); --- -- error: Can not set a savepoint in absence of active transaction +- error: No active transaction ... box.execute('ROLLBACK TO SAVEPOINT t1;'); --- -- error: Can not set a savepoint in absence of active transaction +- error: No active transaction ... box.begin() box.execute('SAVEPOINT t1;') box.execute('RELEASE SAVEPOINT t1;') box.commit(); --- -- 2.21.0