Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
synapse
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Terraform modules
Monitor
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Timo Ley
synapse
Commits
546b9c9e
Unverified
Commit
546b9c9e
authored
3 years ago
by
reivilibre
Committed by
GitHub
3 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Add more tests for in-flight state query duplication. (#12033)
parent
af2c1e3d
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
changelog.d/12033.misc
+1
-0
1 addition, 0 deletions
changelog.d/12033.misc
tests/storage/databases/test_state_store.py
+171
-21
171 additions, 21 deletions
tests/storage/databases/test_state_store.py
with
172 additions
and
21 deletions
changelog.d/12033.misc
0 → 100644
+
1
−
0
View file @
546b9c9e
Deduplicate in-flight requests in `_get_state_for_groups`.
This diff is collapsed.
Click to expand it.
tests/storage/databases/test_state_store.py
+
171
−
21
View file @
546b9c9e
...
...
@@ -18,8 +18,9 @@ from unittest.mock import patch
from
twisted.internet.defer
import
Deferred
,
ensureDeferred
from
twisted.test.proto_helpers
import
MemoryReactor
from
synapse.api.constants
import
EventTypes
from
synapse.storage.state
import
StateFilter
from
synapse.types
import
MutableStateMap
,
StateMap
from
synapse.types
import
StateMap
from
synapse.util
import
Clock
from
tests.unittest
import
HomeserverTestCase
...
...
@@ -27,6 +28,21 @@ from tests.unittest import HomeserverTestCase
if
typing
.
TYPE_CHECKING
:
from
synapse.server
import
HomeServer
# StateFilter for ALL non-m.room.member state events
ALL_NON_MEMBERS_STATE_FILTER
=
StateFilter
.
freeze
(
types
=
{
EventTypes
.
Member
:
set
()},
include_others
=
True
,
)
FAKE_STATE
=
{
(
EventTypes
.
Member
,
"
@alice:test
"
):
"
join
"
,
(
EventTypes
.
Member
,
"
@bob:test
"
):
"
leave
"
,
(
EventTypes
.
Member
,
"
@charlie:test
"
):
"
invite
"
,
(
"
test.type
"
,
"
a
"
):
"
AAA
"
,
(
"
test.type
"
,
"
b
"
):
"
BBB
"
,
(
"
other.event.type
"
,
"
state.key
"
):
"
123
"
,
}
class
StateGroupInflightCachingTestCase
(
HomeserverTestCase
):
def
prepare
(
...
...
@@ -65,24 +81,8 @@ class StateGroupInflightCachingTestCase(HomeserverTestCase):
Assemble a fake database response and complete the database request.
"""
result
:
Dict
[
int
,
StateMap
[
str
]]
=
{}
for
group
in
groups
:
group_result
:
MutableStateMap
[
str
]
=
{}
result
[
group
]
=
group_result
for
state_type
,
state_keys
in
state_filter
.
types
.
items
():
if
state_keys
is
None
:
group_result
[(
state_type
,
"
a
"
)]
=
"
xyz
"
group_result
[(
state_type
,
"
b
"
)]
=
"
xyz
"
else
:
for
state_key
in
state_keys
:
group_result
[(
state_type
,
state_key
)]
=
"
abc
"
if
state_filter
.
include_others
:
group_result
[(
"
other.event.type
"
,
"
state.key
"
)]
=
"
123
"
d
.
callback
(
result
)
# Return a filtered copy of the fake state
d
.
callback
({
group
:
state_filter
.
filter_state
(
FAKE_STATE
)
for
group
in
groups
})
def
test_duplicate_requests_deduplicated
(
self
)
->
None
:
"""
...
...
@@ -125,9 +125,159 @@ class StateGroupInflightCachingTestCase(HomeserverTestCase):
# Now we can complete the request
self
.
_complete_request_fake
(
groups
,
sf
,
d
)
self
.
assertEqual
(
self
.
get_success
(
req1
),
FAKE_STATE
)
self
.
assertEqual
(
self
.
get_success
(
req2
),
FAKE_STATE
)
def
test_smaller_request_deduplicated
(
self
)
->
None
:
"""
Tests that duplicate requests for state are deduplicated.
This test:
- requests some state (state group 42,
'
all
'
state filter)
- requests a subset of that state, before the first request finishes
- checks to see that only one database query was made
- completes the database query
- checks that both requests see the correct retrieved state
"""
req1
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
from_types
(((
"
test.type
"
,
None
),))
)
)
self
.
pump
(
by
=
0.1
)
# This should have gone to the database
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
1
)
self
.
assertFalse
(
req1
.
called
)
req2
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
from_types
(((
"
test.type
"
,
"
b
"
),))
)
)
self
.
pump
(
by
=
0.1
)
# No more calls should have gone to the database, because the second
# request was already in the in-flight cache!
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
1
)
self
.
assertFalse
(
req1
.
called
)
self
.
assertFalse
(
req2
.
called
)
groups
,
sf
,
d
=
self
.
get_state_group_calls
[
0
]
self
.
assertEqual
(
groups
,
(
42
,))
# The state filter is expanded internally for increased cache hit rate,
# so we the database sees a wider state filter than requested.
self
.
assertEqual
(
sf
,
ALL_NON_MEMBERS_STATE_FILTER
)
# Now we can complete the request
self
.
_complete_request_fake
(
groups
,
sf
,
d
)
self
.
assertEqual
(
self
.
get_success
(
req1
),
{(
"
test.type
"
,
"
a
"
):
"
AAA
"
,
(
"
test.type
"
,
"
b
"
):
"
BBB
"
},
)
self
.
assertEqual
(
self
.
get_success
(
req2
),
{(
"
test.type
"
,
"
b
"
):
"
BBB
"
})
def
test_partially_overlapping_request_deduplicated
(
self
)
->
None
:
"""
Tests that partially-overlapping requests are partially deduplicated.
This test:
- requests a single type of wildcard state
(This is internally expanded to be all non-member state)
- requests the entire state in parallel
- checks to see that two database queries were made, but that the second
one is only for member state.
- completes the database queries
- checks that both requests have the correct result.
"""
req1
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
from_types
(((
"
test.type
"
,
None
),))
)
)
self
.
pump
(
by
=
0.1
)
# This should have gone to the database
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
1
)
self
.
assertFalse
(
req1
.
called
)
req2
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
all
()
)
)
self
.
pump
(
by
=
0.1
)
# Because it only partially overlaps, this also went to the database
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
2
)
self
.
assertFalse
(
req1
.
called
)
self
.
assertFalse
(
req2
.
called
)
# First request:
groups
,
sf
,
d
=
self
.
get_state_group_calls
[
0
]
self
.
assertEqual
(
groups
,
(
42
,))
# The state filter is expanded internally for increased cache hit rate,
# so we the database sees a wider state filter than requested.
self
.
assertEqual
(
sf
,
ALL_NON_MEMBERS_STATE_FILTER
)
self
.
_complete_request_fake
(
groups
,
sf
,
d
)
# Second request:
groups
,
sf
,
d
=
self
.
get_state_group_calls
[
1
]
self
.
assertEqual
(
groups
,
(
42
,))
# The state filter is narrowed to only request membership state, because
# the remainder of the state is already being queried in the first request!
self
.
assertEqual
(
s
elf
.
get_success
(
req1
),
{(
"
other.e
vent
.t
ype
"
,
"
state.key
"
):
"
123
"
}
s
f
,
StateFilter
.
freeze
({
E
vent
T
ype
s
.
Member
:
None
},
include_others
=
False
)
)
self
.
_complete_request_fake
(
groups
,
sf
,
d
)
# Check the results are correct
self
.
assertEqual
(
self
.
get_success
(
req2
),
{(
"
other.event.type
"
,
"
state.key
"
):
"
123
"
}
self
.
get_success
(
req1
),
{(
"
test.type
"
,
"
a
"
):
"
AAA
"
,
(
"
test.type
"
,
"
b
"
):
"
BBB
"
},
)
self
.
assertEqual
(
self
.
get_success
(
req2
),
FAKE_STATE
)
def
test_in_flight_requests_stop_being_in_flight
(
self
)
->
None
:
"""
Tests that in-flight request deduplication doesn
'
t somehow
'
hold on
'
to completed requests: once they
'
re done, they
'
re taken out of the
in-flight cache.
"""
req1
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
all
()
)
)
self
.
pump
(
by
=
0.1
)
# This should have gone to the database
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
1
)
self
.
assertFalse
(
req1
.
called
)
# Complete the request right away.
self
.
_complete_request_fake
(
*
self
.
get_state_group_calls
[
0
])
self
.
assertTrue
(
req1
.
called
)
# Send off another request
req2
=
ensureDeferred
(
self
.
state_datastore
.
_get_state_for_group_using_inflight_cache
(
42
,
StateFilter
.
all
()
)
)
self
.
pump
(
by
=
0.1
)
# It should have gone to the database again, because the previous request
# isn't in-flight and therefore isn't available for deduplication.
self
.
assertEqual
(
len
(
self
.
get_state_group_calls
),
2
)
self
.
assertFalse
(
req2
.
called
)
# Complete the request right away.
self
.
_complete_request_fake
(
*
self
.
get_state_group_calls
[
1
])
self
.
assertTrue
(
req2
.
called
)
groups
,
sf
,
d
=
self
.
get_state_group_calls
[
0
]
self
.
assertEqual
(
self
.
get_success
(
req1
),
FAKE_STATE
)
self
.
assertEqual
(
self
.
get_success
(
req2
),
FAKE_STATE
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment