From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\)) Subject: Re: [tarantool-patches] [PATCH 1/2] memtx: add yields during space format check From: Serge Petrenko In-Reply-To: Date: Mon, 3 Jun 2019 18:54:04 +0300 Content-Transfer-Encoding: quoted-printable Message-Id: References: To: tarantool-patches@freelists.org Cc: Vladimir Davydov List-ID: > 3 =D0=B8=D1=8E=D0=BD=D1=8F 2019 =D0=B3., =D0=B2 18:51, Serge Petrenko = =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB(=D0= =B0): >=20 > Just like index build, space check in memtx stalls event loop for the > whole check time. Add occasional yields, and an on_replace trigger, > which checks format for tuples inserted while space format check is in > progress. >=20 > Follow-up #3976 >=20 > @TarantoolBol document =C2=ABTarantoolBol=C2=BB -> =C2=ABTarantoolBot=C2=BB. Sorry, fixed. > Title: memtx now checks space format in background >=20 > There is no event loop stall when memtx engine checks space format > anymore. You may insert tuples into a space, while its new format is > being checked. If the tuples don't match the new format, format change > will be aborted. > --- > src/box/memtx_space.c | 110 ++++++++++++++++++++++++++++++++---------- > 1 file changed, 84 insertions(+), 26 deletions(-) >=20 > diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c > index 1d209033c..a370c038a 100644 > --- a/src/box/memtx_space.c > +++ b/src/box/memtx_space.c > @@ -43,6 +43,16 @@ > #include "column_mask.h" > #include "sequence.h" >=20 > +/* > + * Yield every 1K tuples. > + * In debug mode yield more often for testing purposes. > + */ > +#ifdef NDEBUG > +enum { MEMTX_YIELD_LOOPS =3D 1000 }; > +#else > +enum { MEMTX_YIELD_LOOPS =3D 10 }; > +#endif > + > static void > memtx_space_destroy(struct space *space) > { > @@ -814,6 +824,52 @@ memtx_space_add_primary_key(struct space *space) > return 0; > } >=20 > +/* > + * Ongoing index build or format check state used by > + * corrseponding on_replace triggers. > + */ > +struct memtx_op_state { > + /* The index being built. */ > + struct index *index; > + /* New format to be enforced. */ > + struct tuple_format *format; > + /* Operation cursor. Marks the last processed tuple to date */ > + struct tuple *cursor; > + /* Primary key key_def to compare new tuples with cursor. */ > + struct key_def *cmp_def; > + struct diag diag; > + int rc; > +}; > + > +static void > +memtx_check_on_replace(struct trigger *trigger, void *event) > +{ > + struct txn *txn =3D event; > + struct memtx_op_state *state =3D trigger->data; > + struct txn_stmt *stmt =3D txn_current_stmt(txn); > + > + /* Nothing to check on DELETE. */ > + if (stmt->new_tuple =3D=3D NULL) > + return; > + > + /* We have already failed. */ > + if (state->rc !=3D 0) > + return; > + > + /* > + * Only check format for already processed part of the space, > + * all the tuples inserted below cursor will be checked by the > + * main routine later. > + */ > + if (tuple_compare(state->cursor, HINT_NONE, stmt->new_tuple, = HINT_NONE, > + state->cmp_def) < 0) > + return; > + > + state->rc =3D tuple_validate(state->format, stmt->new_tuple); > + if (state->rc !=3D 0) > + diag_move(diag_get(), &state->diag); > +} > + > static int > memtx_space_check_format(struct space *space, struct tuple_format = *format) > { > @@ -827,8 +883,19 @@ memtx_space_check_format(struct space *space, = struct tuple_format *format) > if (it =3D=3D NULL) > return -1; >=20 > + struct memtx_op_state state; > + state.format =3D format; > + state.cmp_def =3D pk->def->key_def; > + state.rc =3D 0; > + diag_create(&state.diag); > + > + struct trigger on_replace; > + trigger_create(&on_replace, memtx_check_on_replace, &state, = NULL); > + trigger_add(&space->on_replace, &on_replace); > + > int rc; > struct tuple *tuple; > + size_t count =3D 0; > while ((rc =3D iterator_next(it, &tuple)) =3D=3D 0 && tuple !=3D = NULL) { > /* > * Check that the tuple is OK according to the > @@ -837,8 +904,22 @@ memtx_space_check_format(struct space *space, = struct tuple_format *format) > rc =3D tuple_validate(format, tuple); > if (rc !=3D 0) > break; > + if (++count % MEMTX_YIELD_LOOPS =3D=3D 0) { > + state.cursor =3D tuple; > + tuple_ref(state.cursor); > + fiber_sleep(0); > + tuple_unref(state.cursor); > + > + if (state.rc !=3D 0) { > + rc =3D -1; > + diag_move(&state.diag, diag_get()); > + break; > + } > + } > } > iterator_delete(it); > + diag_destroy(&state.diag); > + trigger_clear(&on_replace); > return rc; > } >=20 > @@ -870,25 +951,11 @@ memtx_init_ephemeral_space(struct space *space) > memtx_space_add_primary_key(space); > } >=20 > -/* Ongoing index build state used by memtx_build_on_replace triggers. = */ > -struct memtx_build_state { > - /* The index being built. */ > - struct index *index; > - /* New index format to be enforced. */ > - struct tuple_format *format; > - /* Index build cursor. Marks the last tuple inserted to date */ > - struct tuple *cursor; > - /* Primary key key_def to compare inserted tuples with cursor. = */ > - struct key_def *cmp_def; > - struct diag diag; > - int rc; > -}; > - > static void > memtx_build_on_replace(struct trigger *trigger, void *event) > { > struct txn *txn =3D event; > - struct memtx_build_state *state =3D trigger->data; > + struct memtx_op_state *state =3D trigger->data; > struct txn_stmt *stmt =3D txn_current_stmt(txn); >=20 > struct tuple *cmp_tuple =3D stmt->new_tuple !=3D NULL ? = stmt->new_tuple : > @@ -925,15 +992,6 @@ static int > memtx_space_build_index(struct space *src_space, struct index = *new_index, > struct tuple_format *new_format) > { > - /* > - * Yield every 1K tuples. > - * In debug mode yield more often for testing purposes. > - */ > -#ifdef NDEBUG > - enum { YIELD_LOOPS =3D 1000 }; > -#else > - enum { YIELD_LOOPS =3D 10 }; > -#endif > /** > * If it's a secondary key, and we're not building them > * yet (i.e. it's snapshot recovery for memtx), do nothing. > @@ -959,7 +1017,7 @@ memtx_space_build_index(struct space *src_space, = struct index *new_index, > if (it =3D=3D NULL) > return -1; >=20 > - struct memtx_build_state state; > + struct memtx_op_state state; > state.index =3D new_index; > state.format =3D new_format; > state.cmp_def =3D pk->def->key_def; > @@ -1005,7 +1063,7 @@ memtx_space_build_index(struct space *src_space, = struct index *new_index, > */ > if (new_index->def->iid =3D=3D 0) > tuple_ref(tuple); > - if (++count % YIELD_LOOPS =3D=3D 0) { > + if (++count % MEMTX_YIELD_LOOPS =3D=3D 0) { > /* > * Remember the latest inserted tuple to > * avoid processing yet to be added tuples > --=20 > 2.20.1 (Apple Git-117) >=20 >=20