Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mlangc
Copy link
Contributor

@mlangc mlangc commented Oct 22, 2019

Originally, I tried to implement this like ZIO.memoize. While this approach looks mean and lean for the happy path, getting this right for fatal errors and interruptions is far less trivial (see mlangc@016e264#diff-ba99038d96380b834448ea7c9ddd3c05R776 to get an impression).

The current implementation uses a different approach, that is based on a RefM (this PR also fixes a RefM bug related to fatal errors that hit me). Maybe a normal Ref together with one or more Promises could be used too, at the cost of added complexity.

One last note on the naming: I choose ZManaged.memoize over ZManaged.shared, to emphasize that ZManaged.memoize corresponds directly to ZIO.memoize. Also, shared reminds me of reference counters (maybe from my old C++ times), and might be used to implement different semantics in the future.

Fixes #1263

Copy link
Member

@iravid iravid left a comment

Choose a reason for hiding this comment

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

Hi @mlangc, sorry this waited in the PR queue for so long. The changes look good to me - I left two minor comments.

Could you address them and rebase? I'll merge afterwards. Thanks for working on this useful combinator!

val release1 = (_: Exit[_, _]) => ZIO.unit

val acquire2: ZIO[R, E, ZManaged[R, E, A]] =
ZIO.succeed(ZManaged(ZIO.succeed(Reservation(acquire1, release1))))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
ZIO.succeed(ZManaged(ZIO.succeed(Reservation(acquire1, release1))))
ZIO.succeed(acquire1.toManaged_)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:-) this looks better indeed - thanks for spotting

case Some(cause) => onDefect(cause)
case None =>
update(a).foldM(e => onDefect(Cause.fail(e)) <* promise.fail(e), {
update(a).foldCauseM(c => onDefect(c).ensuring(promise.halt(c)), {
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a test for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course, I will look into this over the weekend.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've just added a test (see fecf6b4). Without the change from above, this test times out.

@mlangc mlangc force-pushed the 1276-zmanaged-memoize branch from 1cd7efc to cb705f3 Compare November 14, 2019 19:58
@mlangc
Copy link
Contributor Author

mlangc commented Nov 14, 2019

@iravid thanks for the review. Strangely enough, rebasing introduced a regression:

[info] ZIO Test
[info] - ZManaged
[info]   - memoize
[info]     - behaves properly if use is interrupted

I will investigate over the weekend, but if you have an idea about the possible cause let me know.

@iravid
Copy link
Member

iravid commented Nov 14, 2019

It's probably related to the autosupervision work.

Another suggestion before you dive into this: I think you can replace RefM with a Ref and a Semaphore. It's a simpler mechanism that is easier to introspect and figure out what goes wrong; RefM has a bunch of moving parts that make it harder to diagnose problems in.

@mlangc
Copy link
Contributor Author

mlangc commented Nov 14, 2019

Thanks for the hints, I'll take that into consideration! I'm still wondering if the regression I see is because of a subtle, intended semantic change, or a because of a regression in another component.

@mlangc mlangc force-pushed the 1276-zmanaged-memoize branch from cb705f3 to 545768b Compare November 17, 2019 13:11
@mlangc
Copy link
Contributor Author

mlangc commented Nov 17, 2019

@iravid I found out more about the test running into a timeout after rebasing with auto supervision: The reason was not that finalizers where not run, but that Fiber.interrupt blocked, because the fiber that consumes the queue in RefM just keeps running. I first fixed the test by forking the interrupt call (see 545768b) - although this seems more like a workaround than a proper solution. The better approach in my opinion is to add daemon to the fiber consuming the Queue in RefM (see 358b188) . What is your take on this?

Note that I can still look into dropping RefM in favor of Ref and Semaphore if you prefer so, but I wanted to find out why auto supervision introduced a regression before.

@iravid
Copy link
Member

iravid commented Nov 17, 2019

@mlangc Ah good catch. Yes, that's one of the "intricacies" with RefM. It may make sense to mark that consumer fiber as ZIO.daemon, but I'd need to think that through.

If you don't want to wait, I would suggest just getting rid of RefM in this combinator for now.

@iravid
Copy link
Member

iravid commented Nov 17, 2019

Actually, I think marking that fiber as ZIO.daemon does make sense, as it should be tied to the lifecycle of RefM, and not to that of the fiber that created RefM.

@mlangc
Copy link
Contributor Author

mlangc commented Nov 17, 2019

@iravid indeed, tying the internal fiber to the live-cycle of the parent fiber is actually wrong, and I've just added a test (see 1b921d3) that demonstrates that (it fails without the daemon).

@iravid
Copy link
Member

iravid commented Nov 17, 2019

Ok, sounds good - thanks for your work on this @mlangc. Will merge when CI is done.

@iravid iravid merged commit 1d8bf38 into zio:master Nov 17, 2019
Twizty pushed a commit to Twizty/zio that referenced this pull request Nov 18, 2019
* Implement `ZManaged.memoize`

Fixes zio#1263

* Correctly handle fatal errors in `RefM`

* Simplify implementation

* Fix test timeout after rebasing with auto supervision

* Add a test that that verifies that `RefM` handles fatal errors

* Make internal `RefM` fiber a daemon fiber and adapt test

* Add test that uses `RefM` after interrupting its parent fiber
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.

Add ZManaged#memoize

2 participants