'Asynchronous AllocateIds operation to reserve the given keys.
Sends one or more v4 AllocateIds rpcs with keys to reserve.
Reserved keys must be complete and must have valid ids.
Args:
config: A Configuration object or None to use Connection default.
keys: Iterable of user-level keys.
extra_hook: Optional function to be called on rpc result.
Returns:
None, or the result of user-supplied extra_hook.'

def _async_reserve_keys(self, config, keys, extra_hook=None):

    def to_id_key(key):
        if (key.path().element_size() == 1):
            return 'root_idkey'
        else:
            return self._extract_entity_group(key)
    keys_by_idkey = self._map_and_group(keys, self.__adapter.key_to_pb, to_id_key)
    max_count = (Configuration.max_allocate_ids_keys(config, self.__config) or self.MAX_ALLOCATE_IDS_KEYS)
    rpcs = []
    pbsgen = self._generate_pb_lists(keys_by_idkey, 0, max_count, None, config)
    for (pbs, _) in pbsgen:
        req = datastore_v4_pb.AllocateIdsRequest()
        for key in pbs:
            datastore_pbs.get_entity_converter().v3_to_v4_key(key, req.add_reserve())
        resp = datastore_v4_pb.AllocateIdsResponse()
        rpcs.append(self._make_rpc_call(config, 'AllocateIds', req, resp, get_result_hook=self.__reserve_keys_hook, user_data=extra_hook, service_name=_DATASTORE_V4))
    return MultiRpc(rpcs)
