File tree Expand file tree Collapse file tree 4 files changed +43
-15
lines changed Expand file tree Collapse file tree 4 files changed +43
-15
lines changed Original file line number Diff line number Diff line change 1
1
import asyncio
2
2
import base64
3
- import binascii
4
3
import collections
5
4
import functools
6
5
import hashlib
18
17
from channels .exceptions import ChannelFull
19
18
from channels .layers import BaseChannelLayer
20
19
20
+ from .utils import _consistent_hash
21
+
21
22
logger = logging .getLogger (__name__ )
22
23
23
24
AIOREDIS_VERSION = tuple (map (int , aioredis .__version__ .split ("." )))
@@ -858,15 +859,7 @@ def deserialize(self, message):
858
859
### Internal functions ###
859
860
860
861
def consistent_hash (self , value ):
861
- """
862
- Maps the value to a node value between 0 and 4095
863
- using CRC, then down to one of the ring nodes.
864
- """
865
- if isinstance (value , str ):
866
- value = value .encode ("utf8" )
867
- bigval = binascii .crc32 (value ) & 0xFFF
868
- ring_divisor = 4096 / float (self .ring_size )
869
- return int (bigval / ring_divisor )
862
+ return _consistent_hash (value , self .ring_size )
870
863
871
864
def make_fernet (self , key ):
872
865
"""
Original file line number Diff line number Diff line change 8
8
import aioredis
9
9
import msgpack
10
10
11
+ from .utils import _consistent_hash
12
+
11
13
logger = logging .getLogger (__name__ )
12
14
13
15
@@ -106,11 +108,7 @@ def _get_shard(self, channel_or_group_name):
106
108
"""
107
109
Return the shard that is used exclusively for this channel or group.
108
110
"""
109
- if len (self ._shards ) == 1 :
110
- # Avoid the overhead of hashing and modulo when it is unnecessary.
111
- return self ._shards [0 ]
112
- shard_index = abs (hash (channel_or_group_name )) % len (self ._shards )
113
- return self ._shards [shard_index ]
111
+ return self ._shards [_consistent_hash (channel_or_group_name , len (self ._shards ))]
114
112
115
113
def _get_group_channel_name (self , group ):
116
114
"""
Original file line number Diff line number Diff line change
1
+ import binascii
2
+
3
+
4
+ def _consistent_hash (value , ring_size ):
5
+ """
6
+ Maps the value to a node value between 0 and 4095
7
+ using CRC, then down to one of the ring nodes.
8
+ """
9
+ if ring_size == 1 :
10
+ # Avoid the overhead of hashing and modulo when it is unnecessary.
11
+ return 0
12
+
13
+ if isinstance (value , str ):
14
+ value = value .encode ("utf8" )
15
+ bigval = binascii .crc32 (value ) & 0xFFF
16
+ ring_divisor = 4096 / float (ring_size )
17
+ return int (bigval / ring_divisor )
Original file line number Diff line number Diff line change
1
+ import pytest
2
+
3
+ from channels_redis .utils import _consistent_hash
4
+
5
+
6
+ @pytest .mark .parametrize (
7
+ "value,ring_size,expected" ,
8
+ [
9
+ ("key_one" , 1 , 0 ),
10
+ ("key_two" , 1 , 0 ),
11
+ ("key_one" , 2 , 1 ),
12
+ ("key_two" , 2 , 0 ),
13
+ ("key_one" , 10 , 6 ),
14
+ ("key_two" , 10 , 4 ),
15
+ (b"key_one" , 10 , 6 ),
16
+ (b"key_two" , 10 , 4 ),
17
+ ],
18
+ )
19
+ def test_consistent_hash_result (value , ring_size , expected ):
20
+ assert _consistent_hash (value , ring_size ) == expected
You can’t perform that action at this time.
0 commit comments