MCPcopy
hub / github.com/redis/redis-py / determine_slot

Method determine_slot

redis/cluster.py:1388–1449  ·  view source on GitHub ↗

Figure out what slot to use based on args. Raises a RedisClusterException if there's a missing key and we can't determine what slots to map the command to; or, if the keys don't all map to the same key slot.

(self, *args)

Source from the content-addressed store, hash-verified

1386 return self.commands_parser.get_keys(redis_conn, *args)
1387
1388 def determine_slot(self, *args) -> Optional[int]:
1389 """
1390 Figure out what slot to use based on args.
1391
1392 Raises a RedisClusterException if there's a missing key and we can't
1393 determine what slots to map the command to; or, if the keys don't
1394 all map to the same key slot.
1395 """
1396 command = args[0]
1397 if self.command_flags.get(command) == SLOT_ID:
1398 # The command contains the slot ID
1399 return args[1]
1400
1401 # Get the keys in the command
1402
1403 # CLIENT TRACKING is a special case.
1404 # It doesn't have any keys, it needs to be sent to the provided nodes
1405 # By default it will be sent to all nodes.
1406 if command.upper() == "CLIENT TRACKING":
1407 return None
1408
1409 # EVAL and EVALSHA are common enough that it's wasteful to go to the
1410 # redis server to parse the keys. Besides, there is a bug in redis<7.0
1411 # where `self._get_command_keys()` fails anyway. So, we special case
1412 # EVAL/EVALSHA.
1413 if command.upper() in ("EVAL", "EVALSHA"):
1414 # command syntax: EVAL "script body" num_keys ...
1415 if len(args) <= 2:
1416 raise RedisClusterException(f"Invalid args in command: {args}")
1417 num_actual_keys = int(args[2])
1418 eval_keys = args[3 : 3 + num_actual_keys]
1419 # if there are 0 keys, that means the script can be run on any node
1420 # so we can just return a random slot
1421 if len(eval_keys) == 0:
1422 return random.randrange(0, REDIS_CLUSTER_HASH_SLOTS)
1423 keys = eval_keys
1424 else:
1425 keys = self._get_command_keys(*args)
1426 if keys is None or len(keys) == 0:
1427 # FCALL can call a function with 0 keys, that means the function
1428 # can be run on any node so we can just return a random slot
1429 if command.upper() in ("FCALL", "FCALL_RO"):
1430 return random.randrange(0, REDIS_CLUSTER_HASH_SLOTS)
1431 raise RedisClusterException(
1432 "No way to dispatch this command to Redis Cluster. "
1433 "Missing key.\nYou can execute the command by specifying "
1434 f"target nodes.\nCommand: {args}"
1435 )
1436
1437 # single key command
1438 if len(keys) == 1:
1439 return self.keyslot(keys[0])
1440
1441 # multi-key command; we need to make sure all keys are mapped to
1442 # the same slot
1443 slots = {self.keyslot(key) for key in keys}
1444 if len(slots) != 1:
1445 raise RedisClusterException(

Callers 4

get_nodes_from_slotMethod · 0.95
_execute_commandMethod · 0.95
execute_commandMethod · 0.80

Calls 4

_get_command_keysMethod · 0.95
keyslotMethod · 0.95
getMethod · 0.45

Tested by

no test coverage detected