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

Fixing hidden infinite loop in the build pending and attach cycle #3355

Merged
merged 8 commits into from
May 28, 2016

Conversation

mkhatib
Copy link
Contributor

@mkhatib mkhatib commented May 27, 2016

Fixes #3354

Tested the test case added before and after the test and it does catches the problem before the change (by disconnecting karma) and passes afterwards.

cc/ @jridgewell @erwinmombay

💯 Thanks to @jridgewell for the awesome quick debugging and the solution proposals in #3354!

for (let i = 0; i < this.pendingBuildResources_.length; i++) {
const resource = this.pendingBuildResources_[i];
if (this.documentReady_ || hasNextNodeInDocumentOrder(resource.element)) {
this.isCurrentlyBuildingPendingResources_ = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do this outside the loop. 😛

Copy link
Contributor Author

Choose a reason for hiding this comment

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

💃 Done

if (this.isCurrentlyBuildingPendingResources_) {
return;
}
this.isCurrentlyBuildingPendingResources_ = true;
Copy link
Member

Choose a reason for hiding this comment

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

Wrap the following in try {…} finally {}. Otherwise an exception can make this stuck forever.

Copy link
Member

Choose a reason for hiding this comment

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

Also test these states in some of the existing tests and maybe throw one in that throws an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That sounds good. Does this mean if one resource keeps failing to build we're going to be stuck and not able to build all other pending resources?

Should we also catch a failed build and remove resource from pending resources?

Copy link
Member

Choose a reason for hiding this comment

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

With the try-finally we should not get stuck. Maybe I misunderstand the question.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The try-finally you were suggesting was for the the full for-loop right? But if the resource.build() step keeps failing we're never taking the resource from the this.pendingBuildResources_ array. So next time the loop is going to run same thing going to happen, no?

Copy link
Member

Choose a reason for hiding this comment

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

I see. Make it so that doesn't happen :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Had to break the method into multiple methods to make it a bit more readable.

Let me know what do you think and if I should add some more test cases.

@mkhatib
Copy link
Contributor Author

mkhatib commented May 27, 2016

PTAL

if (this.documentReady_ || hasNextNodeInDocumentOrder(resource.element)) {
try {
resource.build();
} finally {
Copy link
Member

Choose a reason for hiding this comment

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

Why the finally? This would still throw.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dropped. I seem to have been very sleepy yesterday... Will revert back some of these changes.

@mkhatib
Copy link
Contributor Author

mkhatib commented May 27, 2016

Thanks for the reviews. PTAL

if (this.documentReady_ ||
hasNextNodeInDocumentOrder(resource.element)) {
// Remove resource before build to remove it from the pending list
// in either case the build succeeed or throws an error.
Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about it, is it possible for #build to throw? We have a try-catch already.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah you're right. I kinda skipped this resource.build method and was looking at the element.build.

This might just to be safe not to get stuck in that state of deadlocking. But @cramforce what do you think?

Copy link
Member

Choose a reason for hiding this comment

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

Slightly confused. I think the CL is fine like it is :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we do try/catch already. But if it's critical for this loop - we can add another one.

Copy link
Contributor

Choose a reason for hiding this comment

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

#3355 (comment) is unnecessary because the loop can never throw.

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 am cool with having another try-catch, but I agree with @jridgewell that might not be necessary. Let me know if you guys feel strongly about adding it back.

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's skip try/catch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Skipped.

@mkhatib
Copy link
Contributor Author

mkhatib commented May 27, 2016

PTAL

@@ -392,7 +395,7 @@ export class Resources {
// Build resource immediately, the document has already been parsed.
resource.build();
this.schedulePass();
} else {
} else if (!resource.element.isBuilt()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have the element variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@mkhatib
Copy link
Contributor Author

mkhatib commented May 27, 2016

PTAL

@jridgewell
Copy link
Contributor

LGTM.

@cramforce
Copy link
Member

LGTM

@dvoytenko
Copy link
Contributor

LGTM

@erwinmombay erwinmombay merged commit afefd0d into ampproject:master May 28, 2016
erwinmombay pushed a commit that referenced this pull request May 28, 2016
)

* Only do the build resource loop if we are not already in one.

* Add tests

* outside the loop set flag.

* Protect with try-catch.

* cleanup

* build new resource test.

* Only add to pending if it's not built.

* Add comments.
@mkhatib mkhatib deleted the fix-inf-loop-2 branch May 28, 2016 00:04
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.

5 participants