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
Container Registry
Model registry
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
Maunium
synapse
Commits
ebc3db29
Commit
ebc3db29
authored
10 years ago
by
Paul "LeoNerd" Evans
Browse files
Options
Downloads
Patches
Plain Diff
Take named arguments to @cached() decorator, add a 'max_entries' limit
parent
077d2003
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
synapse/storage/_base.py
+24
-15
24 additions, 15 deletions
synapse/storage/_base.py
synapse/storage/roommember.py
+1
-1
1 addition, 1 deletion
synapse/storage/roommember.py
tests/storage/test__base.py
+89
-0
89 additions, 0 deletions
tests/storage/test__base.py
with
114 additions
and
16 deletions
synapse/storage/_base.py
+
24
−
15
View file @
ebc3db29
...
...
@@ -39,8 +39,8 @@ transaction_logger = logging.getLogger("synapse.storage.txn")
# * Move this somewhere higher-level, shared;
# * more generic key management
# * export monitoring stats
# *
maximum size; just evict things at random, or consider
LRU?
def
cached
(
orig
):
# *
consider other eviction strategies -
LRU?
def
cached
(
max_entries
=
1000
):
"""
A method decorator that applies a memoizing cache around the function.
The function is presumed to take one additional argument, which is used as
...
...
@@ -50,24 +50,33 @@ def cached(orig):
The wrapped function has an additional member, a callable called
"
invalidate
"
. This can be used to remove individual entries from the cache.
"""
cache
=
{}
def
wrap
(
orig
):
cache
=
{}
@defer.inlineCallbacks
def
wrapped
(
self
,
key
):
if
key
in
cache
:
defer
.
returnValue
(
cache
[
key
])
@defer.inlineCallbacks
def
wrapped
(
self
,
key
):
if
key
in
cache
:
defer
.
returnValue
(
cache
[
key
])
ret
=
yield
orig
(
self
,
key
)
while
len
(
cache
)
>
max_entries
:
# TODO(paul): This feels too biased. However, a random index
# would be a bit inefficient, walking the list of keys just
# to ignore most of them?
del
cache
[
cache
.
keys
()[
0
]]
ret
=
yield
orig
(
self
,
key
)
cache
[
key
]
=
ret
;
defer
.
returnValue
(
ret
)
cache
[
key
]
=
ret
;
defer
.
returnValue
(
ret
)
def
invalidate
(
key
):
if
key
in
cache
:
del
cache
[
key
]
def
invalidate
(
key
):
if
key
in
cache
:
del
cache
[
key
]
wrapped
.
invalidate
=
invalidate
return
wrapped
wrapped
.
invalidate
=
invalidate
return
wrapped
return
wrap
class
LoggingTransaction
(
object
):
...
...
This diff is collapsed.
Click to expand it.
synapse/storage/roommember.py
+
1
−
1
View file @
ebc3db29
...
...
@@ -247,7 +247,7 @@ class RoomMemberStore(SQLBaseStore):
results
=
self
.
_parse_events_txn
(
txn
,
rows
)
return
results
@cached
@cached
()
def
get_rooms_for_user
(
self
,
user_id
):
return
self
.
get_rooms_for_user_where_membership_is
(
user_id
,
membership_list
=
[
Membership
.
JOIN
],
...
...
This diff is collapsed.
Click to expand it.
tests/storage/test__base.py
0 → 100644
+
89
−
0
View file @
ebc3db29
# -*- coding: utf-8 -*-
# Copyright 2015 OpenMarket Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from
tests
import
unittest
from
twisted.internet
import
defer
from
synapse.storage._base
import
cached
class
CacheDecoratorTestCase
(
unittest
.
TestCase
):
@defer.inlineCallbacks
def
test_passthrough
(
self
):
@cached
()
def
func
(
self
,
key
):
return
key
self
.
assertEquals
((
yield
func
(
self
,
"
foo
"
)),
"
foo
"
)
self
.
assertEquals
((
yield
func
(
self
,
"
bar
"
)),
"
bar
"
)
@defer.inlineCallbacks
def
test_hit
(
self
):
callcount
=
[
0
]
@cached
()
def
func
(
self
,
key
):
callcount
[
0
]
+=
1
return
key
yield
func
(
self
,
"
foo
"
)
self
.
assertEquals
(
callcount
[
0
],
1
)
self
.
assertEquals
((
yield
func
(
self
,
"
foo
"
)),
"
foo
"
)
self
.
assertEquals
(
callcount
[
0
],
1
)
@defer.inlineCallbacks
def
test_invalidate
(
self
):
callcount
=
[
0
]
@cached
()
def
func
(
self
,
key
):
callcount
[
0
]
+=
1
return
key
yield
func
(
self
,
"
foo
"
)
self
.
assertEquals
(
callcount
[
0
],
1
)
func
.
invalidate
(
"
foo
"
)
yield
func
(
self
,
"
foo
"
)
self
.
assertEquals
(
callcount
[
0
],
2
)
@defer.inlineCallbacks
def
test_max_entries
(
self
):
callcount
=
[
0
]
@cached
(
max_entries
=
10
)
def
func
(
self
,
key
):
callcount
[
0
]
+=
1
return
key
for
k
in
range
(
0
,
12
):
yield
func
(
self
,
k
)
self
.
assertEquals
(
callcount
[
0
],
12
)
# There must have been at least 2 evictions, meaning if we calculate
# all 12 values again, we must get called at least 2 more times
for
k
in
range
(
0
,
12
):
yield
func
(
self
,
k
)
self
.
assertTrue
(
callcount
[
0
]
>=
14
,
msg
=
"
Expected callcount >= 14, got %d
"
%
(
callcount
[
0
]))
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