From: Vladimir Davydov <vdavydov.dev@gmail.com> To: kostja@tarantool.org Cc: tarantool-patches@freelists.org Subject: [PATCH 01/18] vinyl: rework internal quota API Date: Thu, 16 Aug 2018 19:11:55 +0300 [thread overview] Message-ID: <dec06e4254eba0bf22802380c461888d53e30e34.1534432819.git.vdavydov.dev@gmail.com> (raw) In-Reply-To: <cover.1534432819.git.vdavydov.dev@gmail.com> In-Reply-To: <cover.1534432819.git.vdavydov.dev@gmail.com> The API is too generic now. It would be rather difficult to introduce throttling on top of it. Let's rework it to reflect vinyl algorithms. --- src/box/vinyl.c | 28 +++++-------------------- src/box/vy_quota.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 7f779634..d0e822bf 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -2329,7 +2329,7 @@ vinyl_engine_prepare(struct engine *engine, struct txn *txn) * the transaction to be sent to read view or aborted, we call * it before checking for conflicts. */ - if (vy_quota_use(&env->quota, tx->write_size, timeout) != 0) { + if (vy_quota_try_use(&env->quota, tx->write_size, timeout) != 0) { diag_set(ClientError, ER_VY_QUOTA_TIMEOUT); return -1; } @@ -2341,21 +2341,7 @@ vinyl_engine_prepare(struct engine *engine, struct txn *txn) size_t mem_used_after = lsregion_used(&env->mem_env.allocator); assert(mem_used_after >= mem_used_before); size_t write_size = mem_used_after - mem_used_before; - /* - * Insertion of a statement into an in-memory tree can trigger - * an allocation of a new tree block. This should not normally - * result in a noticeable excess of the memory limit, because - * most memory is occupied by statements anyway, but we need to - * adjust the quota accordingly in this case. - * - * The actual allocation size can also be less than reservation - * if a statement is allocated from an lsregion slab allocated - * by a previous transaction. Take this into account, too. - */ - if (write_size >= tx->write_size) - vy_quota_force_use(&env->quota, write_size - tx->write_size); - else - vy_quota_release(&env->quota, tx->write_size - write_size); + vy_quota_commit_use(&env->quota, tx->write_size, write_size); if (rc != 0) return -1; @@ -2512,7 +2498,7 @@ vy_env_dump_complete_cb(struct vy_scheduler *scheduler, size_t mem_used_after = lsregion_used(allocator); assert(mem_used_after <= mem_used_before); size_t mem_dumped = mem_used_before - mem_used_after; - vy_quota_release(quota, mem_dumped); + vy_quota_dump(quota, mem_dumped); say_info("dumped %zu bytes in %.1f sec", mem_dumped, dump_duration); @@ -3214,7 +3200,7 @@ vinyl_space_apply_initial_join_row(struct space *space, struct request *request) * quota accounting. */ size_t reserved = tx->write_size; - if (vy_quota_use(&env->quota, reserved, TIMEOUT_INFINITY) != 0) + if (vy_quota_try_use(&env->quota, reserved, TIMEOUT_INFINITY) != 0) unreachable(); size_t mem_used_before = lsregion_used(&env->mem_env.allocator); @@ -3233,11 +3219,7 @@ vinyl_space_apply_initial_join_row(struct space *space, struct request *request) size_t mem_used_after = lsregion_used(&env->mem_env.allocator); assert(mem_used_after >= mem_used_before); size_t used = mem_used_after - mem_used_before; - if (used >= reserved) - vy_quota_force_use(&env->quota, used - reserved); - else - vy_quota_release(&env->quota, reserved - used); - + vy_quota_commit_use(&env->quota, reserved, used); return rc; } diff --git a/src/box/vy_quota.h b/src/box/vy_quota.h index d741c34a..fd1004da 100644 --- a/src/box/vy_quota.h +++ b/src/box/vy_quota.h @@ -67,7 +67,7 @@ struct vy_quota { /** Current memory consumption. */ size_t used; /** - * If vy_quota_use() takes longer than the given + * If vy_quota_try_use() takes longer than the given * value, warn about it in the log. */ double too_long_threshold; @@ -127,7 +127,7 @@ vy_quota_set_watermark(struct vy_quota *q, size_t watermark) } /** - * Consume @size bytes of memory. In contrast to vy_quota_use() + * Consume @size bytes of memory. In contrast to vy_quota_try_use() * this function does not throttle the caller. */ static inline void @@ -139,10 +139,11 @@ vy_quota_force_use(struct vy_quota *q, size_t size) } /** - * Release @size bytes of memory. + * Function called on dump completion to release quota after + * freeing memory. */ static inline void -vy_quota_release(struct vy_quota *q, size_t size) +vy_quota_dump(struct vy_quota *q, size_t size) { assert(q->used >= size); q->used -= size; @@ -153,9 +154,38 @@ vy_quota_release(struct vy_quota *q, size_t size) * Try to consume @size bytes of memory, throttle the caller * if the limit is exceeded. @timeout specifies the maximal * time to wait. Return 0 on success, -1 on timeout. + * + * Usage pattern: + * + * size_t reserved = <estimate>; + * if (vy_quota_try_use(q, reserved, timeout) != 0) + * return -1; + * <allocate memory> + * size_t used = <actually allocated>; + * vy_quota_commit_use(q, reserved, used); + * + * We use two-step quota allocation strategy (reserve-consume), + * because we may not yield after we start inserting statements + * into a space so we estimate the allocation size and wait for + * quota before committing statements. At the same time, we + * cannot precisely estimate the size of memory we are going to + * consume so we adjust the quota after the allocation. + * + * The size of memory allocated while committing a transaction + * may be greater than an estimate, because insertion of a + * statement into an in-memory index can trigger allocation + * of a new index extent. This should not normally result in a + * noticeable breach in the memory limit, because most memory + * is occupied by statements, but we need to adjust the quota + * accordingly after the allocation in this case. + * + * The actual memory allocation size may also be less than an + * estimate if the space has multiple indexes, because statements + * are stored in the common memory level, which isn't taken into + * account while estimating the size of a memory allocation. */ static inline int -vy_quota_use(struct vy_quota *q, size_t size, double timeout) +vy_quota_try_use(struct vy_quota *q, size_t size, double timeout) { double start_time = ev_monotonic_now(loop()); double deadline = start_time + timeout; @@ -178,6 +208,27 @@ vy_quota_use(struct vy_quota *q, size_t size, double timeout) } /** + * Adjust quota after allocating memory. + * + * @reserved: size of quota reserved by vy_quota_try_use(). + * @used: size of memory actually allocated. + * + * See also vy_quota_try_use(). + */ +static inline void +vy_quota_commit_use(struct vy_quota *q, size_t reserved, size_t used) +{ + if (reserved > used) { + size_t excess = reserved - used; + assert(q->used >= excess); + q->used -= excess; + fiber_cond_broadcast(&q->cond); + } + if (reserved < used) + vy_quota_force_use(q, used - reserved); +} + +/** * Block the caller until the quota is not exceeded. */ static inline void -- 2.11.0
next prev parent reply other threads:[~2018-08-16 16:11 UTC|newest] Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-08-16 16:11 [PATCH 00/18] Implement write throttling for vinyl Vladimir Davydov 2018-08-16 16:11 ` Vladimir Davydov [this message] 2018-08-20 11:07 ` [PATCH 01/18] vinyl: rework internal quota API Konstantin Osipov 2018-08-24 8:32 ` Vladimir Davydov 2018-08-27 18:29 ` Vladimir Davydov 2018-08-16 16:11 ` [PATCH 02/18] vinyl: move quota methods implementation to vy_quota.c Vladimir Davydov 2018-08-20 11:07 ` Konstantin Osipov 2018-08-27 18:30 ` Vladimir Davydov 2018-08-16 16:11 ` [PATCH 03/18] vinyl: move quota related methods and variables from vy_env to vy_quota Vladimir Davydov 2018-08-20 11:08 ` Konstantin Osipov 2018-08-27 18:33 ` Vladimir Davydov 2018-08-16 16:11 ` [PATCH 04/18] vinyl: implement vy_quota_wait using vy_quota_try_use Vladimir Davydov 2018-08-20 11:09 ` Konstantin Osipov 2018-08-27 18:36 ` Vladimir Davydov 2018-08-16 16:11 ` [PATCH 05/18] vinyl: wake up fibers waiting for quota one by one Vladimir Davydov 2018-08-20 11:11 ` Konstantin Osipov 2018-08-24 8:33 ` Vladimir Davydov 2018-08-28 13:19 ` Vladimir Davydov 2018-08-28 14:04 ` Konstantin Osipov 2018-08-28 14:39 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 06/18] vinyl: do not wake up fibers waiting for quota if quota is unavailable Vladimir Davydov 2018-08-20 11:13 ` Konstantin Osipov 2018-08-16 16:12 ` [PATCH 07/18] vinyl: tune dump bandwidth histogram buckets Vladimir Davydov 2018-08-20 11:15 ` Konstantin Osipov 2018-08-28 15:37 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 08/18] vinyl: rename vy_quota::dump_bw to dump_bw_hist Vladimir Davydov 2018-08-20 11:15 ` Konstantin Osipov 2018-08-28 16:04 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 09/18] vinyl: cache dump bandwidth for timer invocation Vladimir Davydov 2018-08-20 11:21 ` Konstantin Osipov 2018-08-28 16:10 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 10/18] vinyl: do not add initial guess to dump bandwidth histogram Vladimir Davydov 2018-08-20 11:23 ` Konstantin Osipov 2018-08-23 20:15 ` Konstantin Osipov 2018-08-28 16:15 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 11/18] vinyl: use snap_io_rate_limit for initial dump bandwidth estimate Vladimir Davydov 2018-08-20 11:24 ` Konstantin Osipov 2018-08-24 8:31 ` Vladimir Davydov 2018-08-28 16:18 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 12/18] histogram: add function for computing lower bound percentile estimate Vladimir Davydov 2018-08-20 11:29 ` [tarantool-patches] " Konstantin Osipov 2018-08-24 8:30 ` Vladimir Davydov 2018-08-28 16:39 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 13/18] vinyl: use lower bound percentile estimate for dump bandwidth Vladimir Davydov 2018-08-28 16:51 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 14/18] vinyl: do not try to trigger dump if it is already in progress Vladimir Davydov 2018-08-16 16:12 ` [PATCH 15/18] vinyl: improve dump start/stop logging Vladimir Davydov 2018-08-23 20:18 ` Konstantin Osipov 2018-08-16 16:12 ` [PATCH 16/18] vinyl: confine quota watermark within sane value range Vladimir Davydov 2018-08-16 16:12 ` [PATCH 17/18] vinyl: set quota timer period to 100 ms Vladimir Davydov 2018-08-23 20:49 ` Konstantin Osipov 2018-08-24 8:18 ` Vladimir Davydov 2018-08-16 16:12 ` [PATCH 18/18] vinyl: throttle tx rate if dump does not catch up Vladimir Davydov 2018-08-23 20:54 ` Konstantin Osipov 2018-08-23 20:58 ` [tarantool-patches] " Konstantin Osipov 2018-08-24 8:21 ` Vladimir Davydov
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=dec06e4254eba0bf22802380c461888d53e30e34.1534432819.git.vdavydov.dev@gmail.com \ --to=vdavydov.dev@gmail.com \ --cc=kostja@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [PATCH 01/18] vinyl: rework internal quota API' \ /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