diff --git a/src/box/vy_point_lookup.c b/src/box/vy_point_lookup.c index 504a8e80d20f1255469f574202e990bcb510ac1f..f2261fdf394ab89d851e7c2060396a0b02719d01 100644 --- a/src/box/vy_point_lookup.c +++ b/src/box/vy_point_lookup.c @@ -203,10 +203,13 @@ vy_point_lookup(struct vy_lsm *lsm, struct vy_tx *tx, int rc = 0; lsm->stat.lookup++; + /* History list */ - struct vy_history history; + struct vy_history history, mem_history, disk_history; vy_history_create(&history, &lsm->env->history_node_pool); -restart: + vy_history_create(&mem_history, &lsm->env->history_node_pool); + vy_history_create(&disk_history, &lsm->env->history_node_pool); + rc = vy_point_lookup_scan_txw(lsm, tx, key, &history); if (rc != 0 || vy_history_is_terminal(&history)) goto done; @@ -215,14 +218,16 @@ vy_point_lookup(struct vy_lsm *lsm, struct vy_tx *tx, if (rc != 0 || vy_history_is_terminal(&history)) goto done; - rc = vy_point_lookup_scan_mems(lsm, rv, key, &history); - if (rc != 0 || vy_history_is_terminal(&history)) +restart: + rc = vy_point_lookup_scan_mems(lsm, rv, key, &mem_history); + if (rc != 0 || vy_history_is_terminal(&mem_history)) goto done; /* Save version before yield */ + uint32_t mem_version = lsm->mem->version; uint32_t mem_list_version = lsm->mem_list_version; - rc = vy_point_lookup_scan_slices(lsm, rv, key, &history); + rc = vy_point_lookup_scan_slices(lsm, rv, key, &disk_history); if (rc != 0) goto done; @@ -241,11 +246,29 @@ vy_point_lookup(struct vy_lsm *lsm, struct vy_tx *tx, * This in unnecessary in case of rotation but since we * cannot distinguish these two cases we always restart. */ - vy_history_cleanup(&history); + vy_history_cleanup(&mem_history); + vy_history_cleanup(&disk_history); goto restart; } + if (mem_version != lsm->mem->version) { + /* + * Rescan the memory level if its version changed while we + * were reading disk, because there may be new statements + * matching the search key. + */ + vy_history_cleanup(&mem_history); + rc = vy_point_lookup_scan_mems(lsm, rv, key, &mem_history); + if (rc != 0) + goto done; + if (vy_history_is_terminal(&mem_history)) + vy_history_cleanup(&disk_history); + } + done: + vy_history_splice(&history, &mem_history); + vy_history_splice(&history, &disk_history); + if (rc == 0) { int upserts_applied; rc = vy_history_apply(&history, lsm->cmp_def, lsm->mem_format, diff --git a/src/box/vy_point_lookup.h b/src/box/vy_point_lookup.h index d74be9a9dabb5c255e0e0349e50ee145d68c0605..3b7c5a04cd8ce5fa2838bec238205ccefa274bf6 100644 --- a/src/box/vy_point_lookup.h +++ b/src/box/vy_point_lookup.h @@ -62,12 +62,9 @@ struct tuple; * tuple in the LSM tree. The tuple is returned in @ret with its * reference counter elevated. * - * The caller must guarantee that if the tuple looked up by this - * function is modified, the transaction will be sent to read view. - * This is needed to avoid inserting a stale value into the cache. - * In other words, vy_tx_track() must be called for the search key - * before calling this function unless this is a primary index and - * the tuple is already tracked in a secondary index. + * Note, this function doesn't track the result in the transaction + * read set, i.e. it is up to the caller to call vy_tx_track() if + * necessary. */ int vy_point_lookup(struct vy_lsm *lsm, struct vy_tx *tx,