[Tarantool-patches] [PATCH v3 2/3] vinyl: clean-up unprocessed read views in *_build_read_views()

Nikita Pettik korablev at tarantool.org
Thu May 7 03:29:22 MSK 2020


On 06 May 12:56, Aleksandr Lyapunov wrote:
> This will work, but I think we have to make the patch better.
> 
> The cause of the issue is that the state of an iterator is not obvious. Is
> the history
> collected or not? Is it merged already? Must it be cleaned up? Even the
> cleanup
> is split to two stages - tuple unrefs and region truncate.
> 
> Now you propose to call  vy_read_view_stmt_destroy from several places that
> also
> unrefs tuples from read view (not only from its history). This makes  the
> state
> of an iterator even more unpredictable: when vy_write_iterator_stop is
> called
> sometimes read views are already cleaned up, sometimes are not.

On the other hand clean-up provided by vy_read_view_stmt_destroy()
is safe: it nullifies rv->tuple and rv->history so that next call
of vy_read_view_stmt_destroy() will be no-op in fact.
Anyway, I've refactored this code according to your plan, so
vy_read_view_stmt_destroy() now unrefs only resulting tuple.

> Let's fix this mess.
> 1. History is collected (rallocated and refed) only in
> vy_write_iterator_build_history.

Check.

> 2. The history must be destructed after call to
> vy_write_iterator_build_history in any case,
> whether an error occurred or not (comment about it?).

But histories are used in vy_read_view_merge(). Do you mean destruct all
histories after they are processed (i.e. before region_truncate())?

> 3. There must be a method for history destruction with two steps: unref all
> and rtruncate.
> 4. Only vy_write_iterator_build_read_views must call this method.
> vy_write_iterator_stop
> or anybody else shouldn't be concerned about history.
> 5. vy_write_iterator_build_read_views must not unref resulting tuples
> (entry.stmt) in case of error,
> vy_write_iterator_stop must do it.

Ok, I agree. I've taken these points into consideration while preparing
next version. Please, check it out. Also here's diff between versions:

diff --git a/src/box/vy_write_iterator.c b/src/box/vy_write_iterator.c
index efb88d1ae..7784dd13a 100644
--- a/src/box/vy_write_iterator.c
+++ b/src/box/vy_write_iterator.c
@@ -151,9 +151,11 @@ vy_read_view_stmt_destroy(struct vy_read_view_stmt *rv)
        if (rv->tuple != NULL)
                vy_stmt_unref_if_possible(rv->tuple);
        rv->tuple = NULL;
-       if (rv->history != NULL)
-               vy_write_history_destroy(rv->history);
-       rv->history = NULL;
+       /*
+        * History must be already cleaned up in
+        * vy_write_iterator_build_read_views().
+        */
+       assert(rv->history == NULL);
 }
 
 /* @sa vy_write_iterator.h */
@@ -790,11 +792,7 @@ next_lsn:
         * statement around if this is major compaction, because
         * there's no tuple it could overwrite.
         */
-       if (rc != 0) {
-               for (int i = 0; i < stream->rv_count; ++i)
-                       vy_read_view_stmt_destroy(&stream->read_views[i]);
-       } else if (stream->is_last_level &&
-                  stream->deferred_delete_stmt != NULL) {
+       if (stream->is_last_level && stream->deferred_delete_stmt != NULL) {
                vy_stmt_unref_if_possible(stream->deferred_delete_stmt);
                stream->deferred_delete_stmt = NULL;
        }
@@ -952,6 +950,25 @@ vy_read_view_merge(struct vy_write_iterator *stream, struct tuple *hint,
        return 0;
 }
 
+/**
+ * Clean up all histories related to given write iterator.
+ * Particular history is allocated using region, so single
+ * region truncation is enough to release all memory at once.
+ * Before that we should also unref tuples stored in those
+ * histories (which is done in vy_write_history_destroy()).
+ */
+static void
+vy_write_iterator_history_destroy(struct vy_write_iterator *stream,
+                                 struct region *region, size_t used)
+{
+       for (int i = 0; i < stream->rv_count; ++i) {
+               if (stream->read_views[i].history != NULL)
+                       vy_write_history_destroy(stream->read_views[i].history);
+               stream->read_views[i].history = NULL;
+       }
+       region_truncate(region, used);
+}
+
 /**
  * Split the current key into a sequence of read view
  * statements. @sa struct vy_write_iterator comment for details
@@ -972,9 +989,12 @@ vy_write_iterator_build_read_views(struct vy_write_iterator *stream, int *count)
        struct region *region = &fiber()->gc;
        size_t used = region_used(region);
        stream->rv_used_count = 0;
+       int rc = 0;
        if (vy_write_iterator_build_history(stream, &raw_count,
-                                           &is_first_insert) != 0)
-               goto error;
+                                           &is_first_insert) != 0) {
+               rc = -1;
+               goto cleanup;
+       }
        if (raw_count == 0) {
                /* A key is fully optimized. */
                region_truncate(region, used);
@@ -996,11 +1016,8 @@ vy_write_iterator_build_read_views(struct vy_write_iterator *stream, int *count)
                        continue;
                if (vy_read_view_merge(stream, hint, rv,
                                       is_first_insert) != 0) {
-                       while (rv >= &stream->read_views[0]) {
-                               vy_read_view_stmt_destroy(rv);
-                               rv--;
-                       }
-                       goto error;
+                       rc = -1;
+                       goto cleanup;
                }
                assert(rv->history == NULL);
                if (rv->tuple == NULL)
@@ -1009,11 +1026,10 @@ vy_write_iterator_build_read_views(struct vy_write_iterator *stream, int *count)
                ++*count;
                hint = rv->tuple;
        }
-       region_truncate(region, used);
-       return 0;
-error:
-       region_truncate(region, used);
-       return -1;
+
+cleanup:
+       vy_write_iterator_history_destroy(stream, region, used);
+       return rc;
 }



More information about the Tarantool-patches mailing list