Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Deduplicate membership changes #700

Merged
merged 4 commits into from Apr 7, 2016

Conversation

Projects
None yet
2 participants
Owner

erikjohnston commented Apr 6, 2016

No description provided.

Contributor

NegativeMjark commented Apr 6, 2016

Is there a reason to only deduplicate joins, or could this be used for all membership changes?

@NegativeMjark NegativeMjark commented on an outdated diff Apr 6, 2016

synapse/handlers/room_member.py
@@ -183,6 +185,44 @@ def update_membership(
third_party_signed=None,
ratelimit=True,
):
+ if action == Membership.JOIN:
+ result = self.join_cache.get((room_id, target))
@NegativeMjark

NegativeMjark Apr 6, 2016

Contributor

Should remote_room_hosts and third_party_signed be part of the request key here?

Contributor

NegativeMjark commented Apr 7, 2016

LGTM

@NegativeMjark NegativeMjark and 1 other commented on an outdated diff Apr 7, 2016

synapse/util/async.py
+
+ with (yield linearizer.queue("test_key")):
+ # do some work.
+
+ """
+ def __init__(self):
+ self.key_to_defer = {}
+
+ @defer.inlineCallbacks
+ def queue(self, key):
+ current_defer = self.key_to_defer.setdefault(key, None)
+
+ new_defer = defer.Deferred()
+ self.key_to_defer[key] = new_defer
+
+ def remove_if_current(_):
@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

Might not want to throw away the thing passed to the callback.

@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

Oh, I see. This is only ever passed the None from _trigger_defer_manager

@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

Would it be clearer to merge the _trigger_defer_manager and the remove_if_current into one thing?

@erikjohnston

erikjohnston Apr 7, 2016

Owner

Possibly, though I think having them split up makes it clearer what each thing is doing.

@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

I think having two functions and an addBoth is less clear in this case.

 @contextmanager
 def manager():
    try:
        yield
     finally:
         d = self.key_to_defer.get(key)
         if d is new_defer:
             self.key_to_defer.pop(key, None)
         d.callback(None)
@erikjohnston

erikjohnston Apr 7, 2016

Owner

Well, your example doesn't actually work, as we specifically don't hit the callback for the most current defer in the list.

I've changed it though I think it just makes things look more complicated.

Contributor

NegativeMjark commented Apr 7, 2016

Maybe add a few comments explaining how the thing is supposed to work inside the queue method.

@NegativeMjark NegativeMjark commented on an outdated diff Apr 7, 2016

synapse/util/async.py
+class Linearizer(object):
+ """Linearizes access to resources based on a key. Useful to ensure only one
+ thing is happening at a time on a given resource.
+
+ Example:
+
+ with (yield linearizer.queue("test_key")):
+ # do some work.
+
+ """
+ def __init__(self):
+ self.key_to_defer = {}
+
+ @defer.inlineCallbacks
+ def queue(self, key):
+ current_defer = self.key_to_defer.setdefault(key, None)
@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

Why is this setdefault rather than get?

erikjohnston added some commits Apr 6, 2016

@erikjohnston erikjohnston changed the title from Deduplicate joins to Deduplicate membership changes Apr 7, 2016

@NegativeMjark NegativeMjark commented on an outdated diff Apr 7, 2016

synapse/util/async.py
+ # resolved.
+ # This all has the net effect of creating a chain of deferreds that
+ # wait for the previous deferred before starting their work.
+ current_defer = self.key_to_defer.get(key)
+
+ new_defer = defer.Deferred()
+ self.key_to_defer[key] = new_defer
+
+ def remove_if_current(_):
+ d = self.key_to_defer.get(key)
+ if d is new_defer:
+ self.key_to_defer.pop(key, None)
+
+ new_defer.addBoth(remove_if_current)
+
+ yield current_defer
@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

Is this going to have the right log context when it resolves?

@NegativeMjark NegativeMjark commented on an outdated diff Apr 7, 2016

synapse/util/async.py
+ # wait for the previous deferred before starting their work.
+ current_defer = self.key_to_defer.get(key)
+
+ new_defer = defer.Deferred()
+ self.key_to_defer[key] = new_defer
+
+ if current_defer:
+ yield preserve_context_over_deferred(current_defer)
+
+ @contextmanager
+ def _ctx_manager(d):
+ try:
+ yield
+ finally:
+ d.callback(None)
+ d = self.key_to_defer.get(key)
@NegativeMjark

NegativeMjark Apr 7, 2016

Contributor

might want to use a different d to avoid confusion.

Contributor

NegativeMjark commented Apr 7, 2016

LGTM

@erikjohnston erikjohnston merged commit a294b04 into develop Apr 7, 2016

8 checks passed

Flake8 + Packaging (Commit) Build #327 origin/erikj/deduplicate_joins succeeded in 29 sec
Details
Flake8 + Packaging (Merged PR) Build finished.
Details
Sytest Postgres (Commit) Build #324 origin/erikj/deduplicate_joins succeeded in 5 min 48 sec
Details
Sytest Postgres (Merged PR) Build finished.
Details
Sytest SQLite (Commit) Build #327 origin/erikj/deduplicate_joins succeeded in 4 min 31 sec
Details
Sytest SQLite (Merged PR) Build finished.
Details
Unit Tests (Commit) Build #371 origin/erikj/deduplicate_joins succeeded in 1 min 18 sec
Details
Unit Tests (Merged PR) Build finished.
Details

@ara4n ara4n referenced this pull request in vector-im/riot-web Apr 13, 2016

Closed

Suppress duplicate joins #531

@richvdh richvdh deleted the erikj/deduplicate_joins branch Dec 1, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment