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

World multithreading #727

Open
wants to merge 77 commits into
base: master
Choose a base branch
from
Open

Conversation

Janmm14
Copy link
Contributor

@Janmm14 Janmm14 commented Jan 28, 2021

Closes #715
Closes #728
Closes #751

Documentation PR: gomint/gomint-docs#28

I'd like to get some hints on what else needs to be made multithread-ready.

TODO:

  • World events (join, leave, load, unload)
  • Command API
  • Console commands
  • permission ticking
  • Easy, standardized API for plugins to read world allow-/blocklist out of config
  • Scoreboards ?!
  • world-limited event listeners
  • External documentation

Current design changes to #715:

  • Only one network manager, but it only ticks worldless connections, otherwise the world ticks the connections
  • New connections are first handled on the old main thread until player joined a world
  • Chat stays on each world's thread, I think that's better than an extra chat thread.

Also contains a bunch of various fixes as well as some javadoc and code layout fixes.

@Janmm14 Janmm14 force-pushed the world-multithreading branch 2 times, most recently from 011c48c to 7502658 Compare January 28, 2021 18:23
Copy link
Member

@geNAZt geNAZt left a comment

Choose a reason for hiding this comment

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

This system should be made with more generic prediction usage. So you can have registerLisetener(T listener, Predicate<Event> shouldFirePredicate) and there is no need to store the IntSet (which is a candidate for hash collisions) since you can use the Collection (which should be moved to the Set interface) in SimplePluginManager eventManager.registerListener(EventListener, Collection<String>) to

eventManager.registerListener(EventListener, Predicate<Event>)

eventManager.registerListener(EventListener, new Predicate<Event>() {
  boolean test(Event event) {
    return !(event instanceof WorldEvent && worlds != null && !worlds.contains(((WorldEvent) event).world().folder()));
  }
})

@geNAZt
Copy link
Member

geNAZt commented Jan 29, 2021

Can you also decouple the API / this reference cleanup from the actual world multithreading? Its hard to review in the current state due to that

@Janmm14

This comment has been minimized.

@geNAZt
Copy link
Member

geNAZt commented Jan 29, 2021

This system should be made with more generic prediction usage. So you can have registerLisetener(T listener, Predicate<Event> shouldFirePredicate) and there is no need to store the IntSet (which is a candidate for hash collisions) since you can use the Collection (which should be moved to the Set interface) in SimplePluginManager eventManager.registerListener(EventListener, Collection<String>) to

eventManager.registerListener(EventListener, Predicate<Event>)

eventManager.registerListener(EventListener, new Predicate<Event>() {
  boolean test(Event event) {
    return !(event instanceof WorldEvent && worlds != null && !worlds.contains(((WorldEvent) event).world().folder()));
  }
})

I used the IntSet, because the WorldManager currently does the same.

Can you link me that usage? If there is a IntSet in use in that Manager its for sure a bug and should be fixed ASAP

@Janmm14

This comment has been minimized.

@Janmm14

This comment has been minimized.

@geNAZt
Copy link
Member

geNAZt commented Jan 29, 2021

Yes, can you open a PR with that here?

@Janmm14

This comment has been minimized.

- split sync and async scheduler api and implementation
- add per-world sync scheduler
- move ticking code from GoMintServer to each world
- create thread in world constructor
- add plugin instance field to plugin class loader and getCallerPluginLoader() method in CallerDetector for world#scheduler() method returning plugin-based
- replace main thread check with world thread check
- synchronize access to Entity#world
- schedule connection close handling onto world thread
- remove sync scheduling from PacketLoginHandler as disconnect is thread safe now
- remove constructor arguments from PacketHandlers
- update world of player to spawnLocation world of PlayerLoginEvent
- make world manager thread safe, start world thread
…WeakReference, clear syncTaskManager on world unload
@Janmm14

This comment has been minimized.

@Janmm14 Janmm14 marked this pull request as draft February 14, 2021 11:59
…or global commands, also add option to disallow console.
- Move server.executorService() to server.asyncScheduler() to be notified about exceptions happening
- move player to world tick earlier, add newConnections list to each world for that
- fix npe in login as spawnLocation can be null
- network manager untick queue is now just an arraylist (enough)
- Change closing behaviour:
  - close network later to be able to kick players
  - disallow new connections when shutting down
  - players get kicked with "Server closed" instead of just connection closing.
 - fix potential watchdog npe when thread is dead
 - report exceptions in world tick and shutdown server
 - uncaught exception handler reports thread id as well
 - added a couple more debug log messages
@Janmm14 Janmm14 marked this pull request as ready for review February 15, 2021 12:08
@Janmm14
Copy link
Contributor Author

Janmm14 commented Feb 15, 2021

I think it might be now ready to merge.
Did some testing and found no more obvious bugs.
Not sure if you want more documentation on certain topics.

@Janmm14 Janmm14 requested a review from geNAZt February 15, 2021 14:17
@Janmm14
Copy link
Contributor Author

Janmm14 commented Feb 15, 2021

A topic to look at is whether we need more safe world access checks, but I think that could be done after merging.

- Remove Command scope system again, Commands are now always bound to active worlds.
- Event listeners are now always bound to active worlds.
- Removed some more unneeded calls to CommandOutput#markFinished
@Janmm14 Janmm14 requested a review from geNAZt March 9, 2021 15:28
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.

Watchdog exception More methods in Plugin class should be final World multithreading
2 participants