async def get_experiment(request, experiment_id): redis = request.app.redis session_id = request['session'].sid try: experiment = json.loads(await redis.hget( hash_key('experiments', experiment_id), experiment_id)) except TypeError as e: print('Error', e) return json_response( {"message": "Invalid experiment. Has it been registered?"}, status=404) print('--- expr', experiment) # TODO check if session in experiment # if not, increase samples # TODO always return same choice for this session print('--', hash_key('samples', experiment_id), experiment_id) policy = POLICIES[experiment.get('policy')] choice_idx = await policy(experiment_id, experiment, redis) print('--- choice_idx', choice_idx) await redis.sadd('samples:%s:%s' % (experiment_id, choice_idx), [session_id]) return json_response({ "message": "Ok.", "choice": choice_idx, })
async def find_node_responsible_for_key(self, key: str): hashed_key = hash_key(key) node_responsible = await self.find_node_responsible_for_addr(hashed_key ) trace_log('SuccRouter: Found the node responsible for key ', key, ' : ', node_responsible) return node_responsible
async def thompson_sampling(experiment_id, experiment, redis): """ Continuously chooses based on observed successes, e.g. Polya's urn. """ choices = experiment['choices'] p = np.zeros(len(choices)) for choice in choices: p[choice] = await redis.scard( # FIXME (what needs fixing here? doh!) hash_key('successes', experiment_id) + ':' + choice) p /= p.sum() return np.random.choice(len(p), p=p)
async def register_experiment(request): redis = request.app.redis experiment_id = uuid.uuid4().hex experiment = EXPERIMENT_SCHEMA.validate(request.json) experiment_exists = await redis.hexists( hash_key('experiments', experiment_id), experiment_id) if experiment_exists: return json_response( {"message": "Experiment by this id already exists."}, status=400) await redis.hset( hash_key('experiments', experiment_id), experiment_id, json.dumps(experiment), ) print('- registered') return json_response({ "message": "New experiment created.", "experiment_id": experiment_id, })
async def copy_to(self, to_node: int, interval: Interval): """ Copy the keys of an interval from our persistant storage to the `to_node`. """ trace_log("KeyTransferer ", self.chord_addr, " : Starting copy of keys from myself to ", to_node) all_keys = await self.persistant_storage.get_keys() keys_to_transfer = [ key for key in all_keys if interval.in_interval(hash_key(key)) ] dict_to_transfer = {} for key in keys_to_transfer: dict_to_transfer[key] = await self.persistant_storage.get(key) await self.copy_key_values_to(to_node, interval, dict_to_transfer)
async def handle_transfer_keys_to_me(self, msg: Message): """ Handle a request to transfer keys to me. """ if self.router == None: return interval, data_dict, copy_node, receiving_node = msg.get_args( ['interval', 'data_dict', 'copy_node', 'receiving_node']) interval = parse_interval_str(interval) receiving_node = int(receiving_node) copy_node = int(copy_node) if debug_log_key_transfers: debug_log("KeyTransferer", self.chord_addr, ": Handling transfer keys from", copy_node, "to", self.chord_addr, "of interval", interval.to_string(), "current-pred", self.router.predecessor, " succ ", self.router.successor) data_to_store = None # Check that we should recieve these and that this is in fact intended for us. if (self.chord_addr == self.router.successor or self.router.predecessor == None): # These are intended for us, because we control everything # Store the data on disk data_to_store = data_dict else: # assert(interval.top == self.chord_addr and interval.top_closed) print("interval is", interval, "predecessor", self.router.predecessor) if (interval.in_interval(self.router.predecessor)): # This means the whole interval isn't for us. # Take out what's ours and foward what ever else there is our_key_range = Interval(self.chord_addr, True, self.router.successor, False) our_keys = set(key for key in data_dict.keys() if our_key_range.in_interval(hash_key(key))) dict_that_is_ours = dict( {key: data_dict[key] for key in our_keys}) other_keys = set(data_dict.keys()).difference(our_keys) dict_that_isnt_ours = { key: data_dict[key] for key in other_keys } # Assume we are the end of the interval, then we need to pass it back wards. other_range = Interval(interval.bottom, interval.bottom_closed, self.router.predecessor, True) # Pass along the rest of the interval await self.copy_key_values_to(self.router.predecessor, other_range, dict_that_isnt_ours) data_to_store = dict_that_is_ours else: # This means we are replicating data_to_store = data_dict # Store the data on disk debug_log("KeyTransferer", self.chord_addr, ": Handling transfer keys from", copy_node, "to", self.chord_addr, "of interval", interval.to_string(), "current-pred", self.router.predecessor, " succ ", self.router.successor, "data", data_to_store) await self.persistant_storage.add_dict(data_to_store) # Confirm what we stored. self.send_confirm_transfer(copy_node, interval, data_dict)
async def handle_set(self, msg: Message): """ Handle a client request to set the value of a key among the chord network. """ if not self.alive: return # Set the key assert ('key' in msg.args and 'value' in msg.args and 'id' in msg.args) key = msg.args['key'] req_id = msg.args['id'] value = msg.args['value'] debug_test("Chord", self.chord_addr,": set request key", key, "to value", value, "with hash", hash_key(key)) node_responsible_addr = await self.router.find_node_responsible_for_key(key) debug_test("Chord", self.chord_addr,": found node responsible for", key, node_responsible_addr) if (node_responsible_addr == self.chord_addr): debug_test("Chord", self.chord_addr,": setting ", key, "to value", value) await self.persistent_storage.set(key, value) debug_test("Chord", self.chord_addr,": setting ", key, "to value", value, "complete") # if config.USING_SUCCESSOR_LIST_REPL: # await self.successor_list.replicate_set_to_successors(key, value) else: set_msg = self.message_sender.create_message(MessageType.SET_VALUE, node_responsible_addr, { 'key': key, 'value' : value }) set_msg_res = await self.keep_resending_until_response(set_msg, lambda msg: msg.has_type(MessageType.SET_VALUE_REPLY) and msg.src == node_responsible_addr) assert('key' in set_msg_res.args and 'value' in set_msg_res.args) assert(set_msg_res.args['key'] == key and set_msg_res.args['value'] == value) self.message_sender.create_and_send_message(MessageType.SET_RESPONSE_TO_BROKER, node_responsible_addr, {'id' : req_id, 'key': str(key), 'value' : value})