kzvezdarov/ircdd — pull request #104 by kzvezdarov (2014-11-24 05:22:22+00:00)
Title: [WIP] Sharded user

Lots of additions to support proper sharding of users and groups.

`RethinkDB` does not have TTL support yet, which forced a lot of less than ideal "heartbeat" mechanics for session handling.

1. Sessions & group state: Users register a session with the `user_sessions` table and periodically heartbeat it. Users also register their session with each group that they have joined via the `user_heartbeats` field of the `group_states` table.

2. The new tables: `user_sessions` and `group_states` basically handle the runtime state of groups and users. `Groups` and `Users` remain as containers for metadata only.

3. Heartbeating is done periodically via `LoopingCall`s.

4. Observation of session information & state is done through `RDB`'s changefeeds. Since each changefeed is an infinite iterator (which blocks until there are more elements in it), the calls to obtain a changefeed return a query runnign on its own connection. Furthermore, the actual changefeed observation is done in separate threads in order to avoid blocking the reactor thread. This means that **any** mutation of the server's state from within the observation threads must be done through `reactor.callFromThread` in order to synchronize properly. Lastly, each connection for each changefeed is forcefully closed on SIGINT in order to "join" the threads to the reactor one and allow for proper shutdown.

5. The `ShardedRealm`'s lookupUser works with the database state properly now. The lookup check is as follows:

First, check for the user in the local realm's data. If the user is found return it.
Second, check in `RDB`. If the user is found there, try to get the session as well. If the session is active that indicates that this user is connected to a different instance somewhere else, so return a Proxy object. If the session is expired/dead, it means that this user is not actually active - fail with NoSuchUser.

The Proxy user is simply a ShardedUser instance whose mind (a.k.a. client connection) is a fake ProxyIRCDDUser. This is so that the local users can interact with remote ones via the same interface.

This is still WIP and needs polishing - specifically, unit and integration test coverage, documentation, and a bit of refactoring to make the logic more evident (and expose problems)