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

Prefix based router support #12

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions nydus/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def _execute(self, attr, args, kwargs):

results = []
for conn in connections:
print conn
Copy link
Collaborator

Choose a reason for hiding this comment

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

print

for retry in xrange(self.max_connection_retries):
try:
results.append(getattr(conn, attr)(*args, **kwargs))
Expand Down
1 change: 1 addition & 0 deletions nydus/db/routers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@

from .base import BaseRouter, RoundRobinRouter

from .prefix_partition import PrefixPartitionRouter
43 changes: 43 additions & 0 deletions nydus/db/routers/prefix_partition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from nydus.db.routers import BaseRouter

class PrefixPartitionRouter(BaseRouter):
'''
Routes based on the configured prefixes

Example config:

'redis': {
'engine': 'nydus.db.backends.redis.Redis',
'router': 'django_redis.nydus_router.PrefixPartitionRouter',
Copy link
Collaborator

Choose a reason for hiding this comment

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

This path needs updated, right?

'hosts': {
0: {'db': 0, 'host': 'default.redis.goteam.be', 'port': 6379},
'user:loves:': {'db': 1, 'host': 'default.redis.goteam.be', 'port': 6379},
'loves:': {'db': 2, 'host': 'default.redis.goteam.be', 'port': 6379},
'hash:entity:': {'db': 0, 'host': 'entities.redis.goteam.be', 'port': 6379},
}
}

We route to one and only one redis.
Use a seperate config if you want hashing based partitioning.
'''

def _route(self, cluster, attr, key, *args, **kwargs):
"""
Perform routing and return db_nums
"""
assert 'default' in cluster.hosts, 'The prefix router requires a default key to route to'
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps I missed something, but is there a default host in your example docstring?

hosts = None
if key:
for host in cluster.hosts:
if key.startswith(str(host)):
hosts = [host]
if not hosts:
hosts = ['default']
elif func == 'pipeline':
raise ValueError('Pipelines requires a key for proper routing')

if not hosts:
raise ValueError, 'I didnt expect this while writing the code so lets fail'
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we fail with a more helpful error message? :) Like "No host found for key?"


return hosts

4 changes: 2 additions & 2 deletions nydus/db/routers/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
:license: Apache License 2.0, see LICENSE for more details.
"""

from nydus.db.routers import RoundRobinRouter
from nydus.db.routers import RoundRobinRouter, PrefixPartitionRouter
from nydus.db.routers.keyvalue import ConsistentHashingRouter, PartitionRouter

__all__ = ('ConsistentHashingRouter', 'PartitionRouter', 'RoundRobinRouter')
__all__ = ('PrefixPartitionRouter', 'ConsistentHashingRouter', 'PartitionRouter', 'RoundRobinRouter')

31 changes: 31 additions & 0 deletions tests/nydus/db/routers/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,37 @@
from nydus.db.routers.keyvalue import ConsistentHashingRouter, PartitionRouter


class PrefixPartitionTest(TestCase):
def test_partitions(self):
'''
Verify if we write ton one and only one redis database
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo in docstring.

'''
from nydus.db import create_cluster
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency, can you move the imports to the top of the file?

import mock
engine = 'nydus.db.backends.redis.Redis'
router = 'nydus.db.routers.redis.PrefixPartitionRouter'
nydus_config = dict(engine=engine, router=router, hosts={
'default': {'db': 0, 'host': 'localhost', 'port': 6379},
'user:loves:': {'db': 1, 'host': 'localhost', 'port': 6379}
})
redis = create_cluster(nydus_config)

keys = [
('user:loves:test', 1),
('default_test',0),
('hash:entity:test', 0)
]

for key, redis_db in keys:
with mock.patch('redis.client.StrictRedis.execute_command') as fake_set:
result = redis.set(key, '1')
args, kwargs = fake_set.call_args
instance, cmd, key, key_value = args
connection_kwargs = instance.connection_pool.connection_kwargs
db = connection_kwargs['db']
self.assertEqual(db, redis_db)


class DummyConnection(BaseConnection):
def __init__(self, i):
self.host = 'dummyhost'
Expand Down