Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] view::async_buffer #1205

Merged
merged 3 commits into from
Sep 5, 2019
Merged

[FEATURE] view::async_buffer #1205

merged 3 commits into from
Sep 5, 2019

Conversation

h-2
Copy link
Member

@h-2 h-2 commented Aug 8, 2019

Enables async I/O even with multiple consumer threads.

Does not yet model View, because it is not Semiregular. I don't mind merging this now and adapting the tests when range-v3 is brought up to date.

TODO:

  • add changelog

@h-2 h-2 requested a review from eseiler August 8, 2019 16:58
@h-2
Copy link
Member Author

h-2 commented Aug 9, 2019

failed macOS tests are due to #1206

include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
@codecov
Copy link

codecov bot commented Aug 12, 2019

Codecov Report

Merging #1205 into master will increase coverage by <.01%.
The diff coverage is 98.24%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1205      +/-   ##
==========================================
+ Coverage   96.83%   96.84%   +<.01%     
==========================================
  Files         218      219       +1     
  Lines        8748     8801      +53     
==========================================
+ Hits         8471     8523      +52     
- Misses        277      278       +1
Impacted Files Coverage Δ
...de/seqan3/range/detail/inherited_iterator_base.hpp 90% <100%> (+0.71%) ⬆️
include/seqan3/range/view/async_input_buffer.hpp 98.14% <98.14%> (ø)
include/seqan3/range/view/take.hpp 97.91% <0%> (-0.13%) ⬇️
...etail/alignment_matrix_column_major_range_base.hpp 100% <0%> (ø) ⬆️
include/seqan3/range/view/take_until.hpp 94.54% <0%> (ø) ⬆️
include/seqan3/range/view/pairwise_combine.hpp 99.02% <0%> (ø) ⬆️
.../seqan3/alignment/matrix/detail/trace_iterator.hpp 100% <0%> (ø) ⬆️
include/seqan3/io/stream/iterator.hpp 100% <0%> (ø) ⬆️
include/seqan3/core/detail/strong_type.hpp 100% <0%> (ø) ⬆️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 96e1db6...ec619e2. Read the comment docs.

@h-2 h-2 requested a review from eseiler August 12, 2019 13:14
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
@h-2 h-2 requested a review from rrahn August 14, 2019 13:20
class async_buffer_iterator
{
//!\brief The sentinel type to compare to.
using sentinel_type = std::ranges::default_sentinel_t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still open

include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved

while ((it != e) && (!stop_producer.load()))// TODO likely
{
auto tmp = std::move(*it);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire function can be reduced to:

void produce()
{
    for (auto it = begin(urange); it != end(urange); ++it)
        if (buffer.wait_push(std::iter_move(it)) == queue_op_status::closed)
            break;

    buffer.close();
}

Then you can directly initialise it as a lambda function in the thread intialisation. But this is not important to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original implementation was very close to this. I changed it after I got dead-locks, but looking at the code right now, I am not sure why exactly (I was under the false impression that try_push would report queue_op_status::full instead queue_op_status::closed if the queue is both full and closed).
I will investigate this again.

test/snippet/range/view/async_buffer.cpp Outdated Show resolved Hide resolved
using test_type = ::testing::Types<iterator_type>;
INSTANTIATE_TYPED_TEST_CASE_P(iterator_fixture, iterator_fixture, test_type);


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double new line

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still open

test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@rrahn rrahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of the minor comments where annotated but actually not fixed. Please check this again.
And we need to discuss another design if you really intend to have consumers not eating up the entire queue. I have layout one idea, but let's discuss this tomorrow with a fresh mind.

* Typically this adaptor is used when you want to consume the entire underlying range; there is no way to stop
* this view from buffering elements before the end of the underlying range is reached other than destructing it.
* If it is destructed before the end of the underlying range is reached, it will stop consuming elements, however,
* those elements that are currently in it's buffer are destructed with it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 No this is a very bad design. If you want to allow that consumers are not consuming everything you need a different signaling mechanism, i.e. consumers signal that they are done reading. The simplest way to do it is by using a barrier then. In that case you need to specify in the construction of the view how many consumers you are expecting and the destructor needs to wait for the consumers to signal they are done (arrived at the barrier managed by the view). Then you can safely destruct the queue even if it is not empy after closing since you are sure that no one is reading from it anymore. I need to think about how you can make it work nicely with the iterator.

test/snippet/range/view/async_buffer.cpp Outdated Show resolved Hide resolved
test/snippet/range/view/async_buffer.cpp Outdated Show resolved Hide resolved
test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
@h-2 h-2 force-pushed the view/async_buffer branch 2 times, most recently from 5f031e5 to 94b3e60 Compare August 21, 2019 15:24
@h-2
Copy link
Member Author

h-2 commented Aug 21, 2019

I have adapted everything according to our discussion.

most of the minor comments where annotated but actually not fixed. Please check this again.

Please review your comments and mark resolved issues as such so that I know which ones you are referring to. (Some things have been changed outside the immediate context so it may appear as there was no change when there was).

@h-2 h-2 requested a review from rrahn August 22, 2019 16:52
class async_buffer_iterator
{
//!\brief The sentinel type to compare to.
using sentinel_type = std::ranges::default_sentinel_t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still open


detail::spin_delay delay{};

assert (buffer_ptr != nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still open

include/seqan3/range/view/async_buffer.hpp Outdated Show resolved Hide resolved
* the underlying range will be invalidated! For underlying ranges that are single-pass, this makes no difference, but
* it might be unexpected for multi-pass ranges (std::ranges::ForwardRange).
*
* Typically this adaptor is used when you want to consume the entire underlying range. While destructing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Typically this adaptor is used when you want to consume the entire underlying range. While destructing
* Typically this adaptor is used when you want to consume the entire underlying range. Destructing

*
* Typically this adaptor is used when you want to consume the entire underlying range. While destructing
* this view before all elements have been read will also stop the thread that moves object from the underlying
* range, it is difficult to assess which elements in the underlying range might still be valid.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* range, it is difficult to assess which elements in the underlying range might still be valid.
* range.

* Typically this adaptor is used when you want to consume the entire underlying range. While destructing
* this view before all elements have been read will also stop the thread that moves object from the underlying
* range, it is difficult to assess which elements in the underlying range might still be valid.
* **In general, assume that it is not safe to access the underlying range separately once it has been passed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* **In general, assume that it is not safe to access the underlying range separately once it has been passed
* **In general, safe access to the underlying range in any other context is not guaranteed and once it has been passed

*
* Note that in addition to the buffer of the view, every iterator has its own one-element-buffer. Dereferencing
* the iterator returns a reference to the element in the buffer, usually you will want to move this element out
* of the buffer with std::move. Incrementing the iterator refills the buffer from the queue inside the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* of the buffer with std::move. Incrementing the iterator refills the buffer from the queue inside the
* of the buffer with std::move or std::iter_move. Incrementing the iterator refills the buffer from the queue inside the

test/snippet/range/view/async_buffer.cpp Outdated Show resolved Hide resolved
using test_type = ::testing::Types<iterator_type>;
INSTANTIATE_TYPED_TEST_CASE_P(iterator_fixture, iterator_fixture, test_type);


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still open

test/unit/range/view/view_async_buffer_test.cpp Outdated Show resolved Hide resolved
@h-2
Copy link
Member Author

h-2 commented Aug 26, 2019

Combinability is broken, don't merge this yet.

@h-2
Copy link
Member Author

h-2 commented Aug 29, 2019

I have addressed the last issues, I think. I even moved the iterator definition out 🤸‍♂️

@h-2 h-2 force-pushed the view/async_buffer branch 2 times, most recently from 06e93f2 to 414a66f Compare August 29, 2019 16:12
@h-2
Copy link
Member Author

h-2 commented Aug 29, 2019

Fixed the test failure.

Copy link
Contributor

@rrahn rrahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor questions left

//!\brief Post-increment.
void operator++(int) noexcept
{
++(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this iterator becomes no Cpp17Iterator. In case this matters.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value_type x = *i;
++i;
return x;

*i++ -> convertible to value_type

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And further down:

typename std::common_reference_t<decltype(*i++)&&, typename std::readable_traits::value_type&>;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, but we wouldn't be able to satisfy "equivalent expression" in any case, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we leave it as no CPP17Iterator. You might want to add then a sentence to the view description that the returned iterator does not model Cpp17InputIterator. After this we can merge it.

@h-2 h-2 requested a review from rrahn September 2, 2019 12:11
Copy link
Contributor

@rrahn rrahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment about not modeling Cpp17InputIterator to the view documentation.

Copy link
Contributor

@rrahn rrahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💅 only minor stuff

* And we want it to happen to make sure we don't dead-lock on it.
*/
std::this_thread::sleep_for(std::chrono::milliseconds(100));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line

@rrahn
Copy link
Contributor

rrahn commented Sep 3, 2019

CI is broken

Copy link
Contributor

@rrahn rrahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one more test, than I am happy 😏

EXPECT_FALSE(std::ranges::SizedRange<decltype(v1)>);
EXPECT_FALSE(ConstIterableRange<decltype(v1)>);
EXPECT_TRUE(std::ranges::View<decltype(v1)>);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add one more test with an empty range.

@h-2
Copy link
Member Author

h-2 commented Sep 5, 2019

Jenkins failure unrelated.

@h-2 h-2 merged commit c376e88 into seqan:master Sep 5, 2019
@h-2 h-2 mentioned this pull request Sep 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants