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

Fix internal policy of event.Bus events publishing #8110

Merged
merged 2 commits into from
Feb 12, 2018
Merged

Fix internal policy of event.Bus events publishing #8110

merged 2 commits into from
Feb 12, 2018

Conversation

voievodin
Copy link
Contributor

Hi there ✋

This pull request fixed the behaviour of events publishing in Golang based event bus.
The current version of Bus.Pub func:

func (bus *Bus) Pub(e E) {
	bus.RLock()
	defer bus.RUnlock()
	cons, ok := bus.consumers[e.Type()]
	if ok {
		for idx, v := range cons {
			v.Accept(e)
			if tmpCons, ok := v.(TmpConsumer); ok && tmpCons.IsDone() {
				bus.rm(e.Type(), idx) // <= oops
			}
		}
	}
}

The main problem here is modification of bus state within the read lock in case consumer is instance of TmpConsumer and call to isDone returns true. One of the commits introduces a test-case that breaks the behaviour of this function and ends up throwing one of the following errors:

panic: runtime error: slice bounds out of range
fatal error: concurrent map writes

To solve the problem copy-on-write approach was used. So basically each time there is a new subscription or consumer removal the original array of consumers is replaced with a new one. It allows concurrently publishing go-routines to complete without any errors. This approach is similar to the one used by EventService.

@benoitf benoitf added kind/bug Outline of a bug - must adhere to the bug report template. status/code-review This issue has a pull request posted for it and is awaiting code review completion by the community. labels Jan 1, 2018
@codenvy-ci
Copy link

Can one of the admins verify this patch?

1 similar comment
@codenvy-ci
Copy link

Can one of the admins verify this patch?

@skabashnyuk
Copy link
Contributor

ci-test

@garagatyi
Copy link

Hi @voievodin! Nice to see you again. Can you sign your commits to satisfy eclipse ip check?

@codenvy-ci
Copy link

}

// SubAny does the same as Sub func, but for multiple event types.
func (bus *Bus) SubAny(consumer Consumer, types ...string) {
bus.Lock()
defer bus.Unlock()
for _, t := range types {
bus.consumers[t] = append(bus.consumers[t], consumer)
bus.consumers[t] = append(bus.copyConsumers(t), consumer)
}

Choose a reason for hiding this comment

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

Since the whole function is covered by a lock do we really need to copy consumers before appending the new one?

@@ -81,19 +82,20 @@ func (bus *Bus) Pub(e E) {
func (bus *Bus) Sub(consumer Consumer, eType string) {
bus.Lock()
defer bus.Unlock()
bus.consumers[eType] = append(bus.consumers[eType], consumer)
bus.consumers[eType] = append(bus.copyConsumers(eType), consumer)

Choose a reason for hiding this comment

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

Since the whole function is covered by a lock do we really need to copy consumers before appending the new one?

Copy link
Contributor Author

@voievodin voievodin Jan 4, 2018

Choose a reason for hiding this comment

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

Technically it will work without copying, as a new element will be added to the underlining array while concurrently reading(publishing) go routines will be working with slices referencing the same array but different elements.

The reason i changed this code was to achieve the same copy-on-write pattern concept throughout all bus state modification functions. For example Bus.rm copies values because otherwise it would change the original values of underlining array, including those being concurrently referenced by reading routines, which may produce unexpected results. Fail-safe traversing, simplicity are the main reasons.

If we take a look at EventService java implementation it carries ConcurrentMapof CopyOnWriteArraySets, so each write produces a new instance of underlining array, which is the same approach in terms of modification.

Choose a reason for hiding this comment

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

I thought that it always creates a new array, but now I see that there are cases when the slice is just resliced.
Thank you for the explanation.

@codenvy-ci
Copy link

Can one of the admins verify this patch?

@voievodin
Copy link
Contributor Author

I'm not sure i can pass CLA check as i have no access to my previous email.
I would appreciate if some of you guys commit these changes and merge them.
Thank you in advance!

@benoitf
Copy link
Contributor

benoitf commented Feb 9, 2018

@voievodin just register your new gmail through Eclipse ECA

here is the link https://accounts.eclipse.org/user/login?destination=user/eca

@voievodin
Copy link
Contributor Author

voievodin commented Feb 9, 2018

@benoitf How does it work for the users not from the Eclipse organization?
I mean if someone wants to make contribution to the project, does it mean he/she must also pass the check?

@benoitf
Copy link
Contributor

benoitf commented Feb 9, 2018

@voievodin yes it's for all external contributors
All external contributors should sign ECA and add their email as Signed-Off in the commit

@voievodin
Copy link
Contributor Author

@benoitf thank you, i will register and pass the validation =)

Signed-off-by: Yevhenii Voievodin <targetjump@gmail.com>
Signed-off-by: Yevhenii Voievodin <targetjump@gmail.com>
@voievodin
Copy link
Contributor Author

@garagatyi, @akorneta all checks passed, feel free to merge when necessary

Copy link
Contributor

@benoitf benoitf left a comment

Choose a reason for hiding this comment

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

ci-build

@skabashnyuk
Copy link
Contributor

@voievodin thx

@akorneta akorneta merged commit bf14f2f into eclipse-che:master Feb 12, 2018
@benoitf benoitf removed the status/code-review This issue has a pull request posted for it and is awaiting code review completion by the community. label Feb 12, 2018
@benoitf benoitf added this to the 6.1.0 milestone Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Outline of a bug - must adhere to the bug report template.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants