def __init__(self, outfile, start_time, step_size, win_size, num_workers=2, workers=None): logger.info("Created master class") self.outfile = outfile self.num_workers = num_workers self.non_skyline = [] self.sky_received = 0 self.unprocessed_sky = [] self.recv_workers = {} self.start_time = start_time self.window_time = start_time self.win_size = win_size self.step = 0 self.step_size = step_size self.last_received_time = time.time() self.is_running = False self.is_waiting = False self.is_computing = False self.have_new_data = False self.status_lock = threading.Lock() self.data_lock = threading.Lock() self.sky = Skyline() self.skyline = [] self.skylines = {} self.skyline_changes = {}
def visitRandom_skyline(self, ctx: SkylineParser.Random_skylineContext): nodes = [w for w in ctx.children] n = int(nodes[0].getText()) if n < 1: print("Invalid N!!") return Skyline() hmax = int(nodes[2].getText()) if hmax < 1: print("Invalid height!!") return Skyline() wmax = int(nodes[4].getText()) if wmax < 1: print("Invalid width!!") return Skyline() xmin = int(nodes[6].getText()) xmax = int(nodes[8].getText()) if xmax <= xmin: print("Invalid x-coord range!!") return Skyline() return Skyline(n, hmax, wmax, xmin, xmax)
def __init__(self, infile, master, process_line=None, work_id=None): self.infile = infile self.inputf = open(infile, 'r') self.master_url = master if work_id is not None: self.worker_id = work_id else: self.worker_id = create_nonce(10) handler = logging.StreamHandler(stream=sys.stdout) # logger = logging.FileHandler("worker-{}.log".format(self.worker_id)) formatter = logging.Formatter("%(asctime)s: %(levelname)s: %(name)s: " "%(message)s") self.logger = logging.getLogger(self.worker_id) self.logger.setLevel(logging.DEBUG) handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) self.logger.addHandler(handler) # logging.getLogger('').addHandler(logger) # logging.getLogger('').setLevel(logging.DEBUG) # self.logger = logging.getLogger(self.worker_id) self.process_line = json.loads if process_line is not None: self.process_line = process_line # verify that we can actually talk to the master by trying to # get information about the step size self.verify_master() # create the skyline stuff self.sky = Skyline() self.old_skys = {}
def loadSkyline(self, id, username): try: sk = Skyline() nameToLoad = id+username sk = sk.getSkyline('{}{}.sky'.format(self.SkyDBRoot, nameToLoad)) self.taulaSimbols[id] = sk sk.mostrar(self.file) return sk except Exception as _: print('No tinc aquest Skyline guardat') return (None, 'No tinc aquest Skyline guardat')
def visitThreenums(self, ctx: SkylineParser.ThreenumsContext): """ Realitza la operació de creació d'un edifici i el retorna """ lst = [n for n in ctx.getChildren()] i = int(lst[0].getText()) h = int(lst[2].getText()) f = int(lst[4].getText()) sl = Skyline(initial=i, height=h, final=f) return sl
def visitAssignment(self, ctx: SkylineParser.AssignmentContext): nodes = [w for w in ctx.children] name: str = nodes[0].getText() new_skyline = Skyline(self.visit(nodes[2])) print(name, self.user_skylines) self.user_skylines[name] = new_skyline print(name, self.user_skylines) return new_skyline
def visitAssign(self, ctx: SkylineParser.AssignContext): l = [n for n in ctx.getChildren()] # ID id = l[0].getText() # sky: para guardar en la ts if len(l) == 3: sky = self.visit(l[2]) self.user_data = sk.update_symbols(id, self.user_data, sky) return sky
def visitValue(self, ctx: SkylineParser.ValueContext): n = next(ctx.getChildren()) if ctx.NUM(): return int(n.getText()) elif ctx.building(): xmin, top, xmax = self.visit(n) return Skyline.single(xmin, top, xmax) elif ctx.city(): return self.visit(n)
def visitMultiple(self, ctx: SkylineParser.MultipleContext): start = [] height = [] width = [] for x in ctx.building(): xmin, top, xmax = self.visit(x) start.append(xmin) height.append(top) width.append(xmax - xmin) return Skyline(start, height, width)
def visitFivenums(self, ctx: SkylineParser.FivenumsContext): """ Realitza la operació de creació de Skyline random """ lst = [n for n in ctx.getChildren()] sln = int(lst[0].getText()) slh = int(lst[2].getText()) slw = int(lst[4].getText()) slXMin = int(lst[6].getText()) slXMax = int(lst[8].getText()) sl = Skyline(n=sln, h=slh, w=slw, xmin=slXMin, xmax=slXMax) return sl
def visitThreenums(self, ctx: SkylineParser.ThreenumsContext): """ Mètode de representació d'un skyline amb un edifici """ l = [n for n in ctx.getChildren()] i = int(l[0].getText()) h = int(l[2].getText()) f = int(l[4].getText()) sl = Skyline(initial=i, height=h, final=f) self.nivell += 2 print(" " * self.nivell + ("%s" % sl)) self.nivell -= 2 return sl
def visitEdifici(self, ctx: SkylineParser.EdificiContext): # Agafem els seus fills i ens quedem amb xmin, altura, xmax fills = [n for n in ctx.getChildren()] # Si només rebem un fill es que el edifici està dins una variable if (len(fills) == 1): fill = self.visit(fills[0]) return fill # Sinó, vol dir que estem rebent un edifici de la forma (xmin,altura,xmax) elif (len(fills) == 7): xmin = self.visit(fills[1]) altura = self.visit(fills[3]) xmax = self.visit(fills[5]) # Creem un nou Skyline i el retornem amb les dades corresponents newSk = Skyline() newSk.afegir(xmin, altura, xmax) return newSk else: return (None, 'L\'edifici no està ben definit')
def visitEdificiAleatori(self, ctx: SkylineParser.EdificiAleatoriContext): # Agafem dels seus fills i ens qedem amb els parametres que ens interessen fills = [n for n in ctx.getChildren()] n = self.visit(fills[1]) h = self.visit(fills[3]) w = self.visit(fills[5]) xmin = self.visit(fills[7]) xmax = self.visit(fills[9]) newSk = Skyline() # Anem creant tants edificis com ens demanin for edifici in range(0, n): # Calculem aleatoriament cada edifici random.seed() newH = random.randint(1, h) newW = random.randint(1, w) newXmin = random.randint(xmin, xmax - newW) newXmax = newXmin + newW newSk.afegir(newXmin, newH, newXmax) return newSk
def visitEdificis(self, ctx: SkylineParser.EdificisContext): # Agafem dels seus fills els diferents edificis fills = [n for n in ctx.getChildren()] # Creem un nou Skyline (sera el que retornarem) newSk = Skyline() for f in fills: # Anem afegint al newSk els diversos edificis sk = self.visit(f) if (type(sk) is Skyline): newSk = newSk + sk return newSk
def visitSky(self, ctx: SkylineParser.SkyContext): l = [n for n in ctx.getChildren()] # true si es NUM, ID check = hasattr(l[0], 'getSymbol') # get ID if check: get_id = l[0].getText() get_sky = sk.find_symbol(get_id, self.user_data) if get_sky is None: raise Exception("El Skyline con id: " + get_id + " no esta en la tabla de simbolos") return get_sky else: return self.visit(l[0])
def visitRandom(self, ctx: SkylineParser.RandomContext): n = self.visit(ctx.getChild(1)) h = self.visit(ctx.getChild(3)) w = self.visit(ctx.getChild(5)) xmin = self.visit(ctx.getChild(7)) xmax = self.visit(ctx.getChild(9)) eds = [] for _ in range(n): x = random.randint(xmin, xmax) alçada = random.randint(0, h) amplada = random.randint(1, w) eds.append([x, alçada, x + amplada]) return Skyline(eds)
def visitFivenums(self, ctx: SkylineParser.FivenumsContext): """ Mètode de representació d'un Skyline creat de forma random """ l = [n for n in ctx.getChildren()] sln = int(l[0].getText()) slh = int(l[2].getText()) slw = int(l[4].getText()) slxmin = int(l[6].getText()) slxmax = int(l[8].getText()) sl = Skyline(n=sln, h=slh, w=slw, xmin=slxmin, xmax=slxmax) self.nivell += 2 print(" " * self.nivell + ("%s" % sl)) self.nivell -= 2 return sl
def visitAleatorio(self, ctx: SkylineParser.AleatorioContext): l = [n for n in ctx.getChildren()] if 0 > int(l[1].getText()): raise Exception("El numero a crear de skylines no puede ser negativo") if 0 > int(l[3].getText()): raise Exception("La altura del Skyline no puede ser negativa") if 0 > int(l[5].getText()): raise Exception("El width no puede ser menor que 1") if int(l[7].getText()) >= int(l[9].getText()): raise Exception("Max no puede ser menor que Min") alea_sky = sk.random_skylines(int(l[1].getText()), int(l[3].getText()), int(l[5].getText()), int(l[7].getText()), int(l[9].getText())) return alea_sky
def save_id(update, context): print('saving') # recoger el Skyline de la ts sky_save = sk.find_symbol(context.args[0], context.user_data['ts']) # Si no existe: if sky_save is None: context.bot.send_message(chat_id=update.effective_chat.id, text="El id no existe, intentalo de nuevo") try: with open(context.args[0] + '.sky', 'wb') as user_file: pickle.dump(sky_save, user_file) print('saved') except Exception as e: context.bot.send_message(chat_id=update.effective_chat.id, text=str(e)) context.bot.send_message(chat_id=update.effective_chat.id, text="El skyline ha sido guardado")
def visitRandom(self, ctx: SkylineParser.RandomContext): l = [self.visit(n) for n in ctx.expr()] for x in l: if not isinstance(x, int): raise Exception( "El valors en {n, h, w, xmin, xmax} han de ser enters.") if (l[0] < 0): raise Exception("Nombre d'edificis negatius: " + str(l[0])) if (l[1] < 0): raise Exception("Alçada negativa: " + str(l[1])) if (l[2] <= 0): raise Exception("Amplada inferior a 1: " + str(l[2])) if (l[4] <= l[3]): raise Exception( "La posició final ha de ser més gran que la inicial: " + str(l[3]) + '>' + str(l[4])) return Skyline.random(l[0], l[1], l[2], l[3], l[4])
def load_id(update, context): up_sky = sk(0, 0, 0) try: with open(context.args[0] + '.sky', 'rb') as n_sky: up_sky = pickle.load(n_sky) except (OSError, IOError) as e: context.bot.send_message(chat_id=update.effective_chat.id, text="No hay un archivo de ese nombre") # Si existe, (sobre)excribo en: try: context.user_data['ts'] = sk.update_symbols(context.args[0], context.user_data['ts'], up_sky) print('updated') except Exception as e: context.bot.send_message(chat_id=update.effective_chat.id, text=str(e)) context.bot.send_message( chat_id=update.effective_chat.id, text="Se ha cargado el archivo en la tabla de simbolos")
def process_skyline(self): """Script to process the skyline for each new data point There are 2 phases to this: 1) update the individual skyline 2) update the global skyline from the individuals """ work_seen = {} global_seen = {} try: # update each local skyline for sky in self.unprocessed_sky: worker = sky['worker_id'] added, removed = sky['added'], sky['removed'] work_seen[worker] = {} logger.debug("starting to process: {} {} {}" "".format(worker, added, removed)) # add and remove the entries if worker not in self.skylines: self.skylines[worker] = Queue.Queue() # remove the entries we don't need # remove logger.debug("here 1") to_see = self.skylines[worker].qsize() for idx in range(to_see): # remove logger.debug("removing") item = self.skylines[worker].get_nowait() if item in removed: logger.debug("{} in removed".format(item)) continue self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item # and add the new entries # remove logger.debug("here 2") for item in added: # remove logger.debug("adding") self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item logger.debug("skylines: {}".format(work_seen)) # self.step = item['step'] # remove logger.debug("here 3") # now update the global skyline based on the items self.sky = Skyline() for key in global_seen: # remove logger.debug("updating point {}".format(item)) item = global_seen[key] self.sky.update_sky_for_point(item) # snapshot the global skyline skys = {} self.skyline = [] to_see = self.sky.skyline.qsize() for x in range(to_see): item = self.sky.skyline.get_nowait() key = tuple(item['data'] + [item['step']]) skys[key] = item self.sky.skyline.put(item) # remove logger.debug("skyline point {}".format(item)) self.skyline.append(item) new_keys = set(skys.keys()) logger.debug("Global skyline is: {}".format(self.skyline)) # return the difference to each worker for worker in work_seen: old_keys = set(work_seen[worker].keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: work_seen[worker][x], removed) update = { 'step': self.step, 'added': added, 'removed': removed, 'worker_id': worker } self.skyline_changes[worker] = update logger.debug("skyline changes {}".format(update)) self.unprocessed_sky = [] self.recv_workers = {} self.sky_received = 0 except (SystemExit, KeyboardInterrupt) as exp: logger.info("Received keyboard interrupt") raise (exp) except Exception: # traceback.print_exc() logger.exception("problem in processing skyline")
class Master(): def __init__(self, outfile, start_time, step_size, win_size, num_workers=2, workers=None): logger.info("Created master class") self.outfile = outfile self.num_workers = num_workers self.non_skyline = [] self.sky_received = 0 self.unprocessed_sky = [] self.recv_workers = {} self.start_time = start_time self.window_time = start_time self.win_size = win_size self.step = 0 self.step_size = step_size self.last_received_time = time.time() self.is_running = False self.is_waiting = False self.is_computing = False self.have_new_data = False self.status_lock = threading.Lock() self.data_lock = threading.Lock() self.sky = Skyline() self.skyline = [] self.skylines = {} self.skyline_changes = {} def process_skyline(self): """Script to process the skyline for each new data point There are 2 phases to this: 1) update the individual skyline 2) update the global skyline from the individuals """ work_seen = {} global_seen = {} try: # update each local skyline for sky in self.unprocessed_sky: worker = sky['worker_id'] added, removed = sky['added'], sky['removed'] work_seen[worker] = {} logger.debug("starting to process: {} {} {}" "".format(worker, added, removed)) # add and remove the entries if worker not in self.skylines: self.skylines[worker] = Queue.Queue() # remove the entries we don't need # remove logger.debug("here 1") to_see = self.skylines[worker].qsize() for idx in range(to_see): # remove logger.debug("removing") item = self.skylines[worker].get_nowait() if item in removed: logger.debug("{} in removed".format(item)) continue self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item # and add the new entries # remove logger.debug("here 2") for item in added: # remove logger.debug("adding") self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item logger.debug("skylines: {}".format(work_seen)) # self.step = item['step'] # remove logger.debug("here 3") # now update the global skyline based on the items self.sky = Skyline() for key in global_seen: # remove logger.debug("updating point {}".format(item)) item = global_seen[key] self.sky.update_sky_for_point(item) # snapshot the global skyline skys = {} self.skyline = [] to_see = self.sky.skyline.qsize() for x in range(to_see): item = self.sky.skyline.get_nowait() key = tuple(item['data'] + [item['step']]) skys[key] = item self.sky.skyline.put(item) # remove logger.debug("skyline point {}".format(item)) self.skyline.append(item) new_keys = set(skys.keys()) logger.debug("Global skyline is: {}".format(self.skyline)) # return the difference to each worker for worker in work_seen: old_keys = set(work_seen[worker].keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: work_seen[worker][x], removed) update = {'step': self.step, 'added': added, 'removed': removed, 'worker_id': worker} self.skyline_changes[worker] = update logger.debug("skyline changes {}".format(update)) self.unprocessed_sky = [] self.recv_workers = {} self.sky_received = 0 except (SystemExit, KeyboardInterrupt) as exp: logger.info("Received keyboard interrupt") raise(exp) except Exception: # traceback.print_exc() logger.exception("problem in processing skyline") def write_out_skyline(self): logger.info("Writing out skyline") entry = {'step': self.step - 1, 'data': self.skyline} self.output.write(json.dumps(entry) + "\n") def run_loop(self): # open output file self.output = open(self.outfile, 'w') # initialize our variables self.status_lock.acquire() self.is_running = True self.is_waiting = True self.is_computing = False self.step = 0 self.window_time = self.start_time self.status_lock.release() logger.info("Starting background thread loop") # the main run loop will see if the web server has brought us # any goodies, then run the skyline if possible or preempt for # a few seconds until we can keep_running = True try: while keep_running: self.status_lock.acquire() # logger.debug("running: {}".format(keep_running)) # if we are out of workers, then quit if self.num_workers <= 0: logger.info("Out of workers, so quitting") self.status_lock.release() keep_running = False continue # if we don't have anything new, preempt until we have # something. If we have waited more than the timeout # period, then end # if not self.have_new_data: if self.sky_received != self.num_workers: time_since_update = time.time() - self.last_received_time if (time_since_update > MASTER_TIMEOUT_TO_END): logger.info("Didn't receive anything in the " "timeout, so ending") self.status_lock.release() keep_running = False continue self.status_lock.release() logger.debug("waiting for new data") time.sleep(MASTER_WAIT_TIME) continue # check how many workers have given us the skyline for # this timestep to determine if we can compute the # skyline if self.sky_received == self.num_workers: logger.debug("Received data from all workers, so " "starting to compute") self.waiting = False self.is_computing = True self.sky_received = 0 self.step += 1 time_elapsed = (self.step * self.step_size) self.window_time = self.start_time + time_elapsed self.status_lock.release() self.data_lock.acquire() self.process_skyline() # now that we have finished a round, write out the # data and increment the step self.write_out_skyline() self.data_lock.release() self.status_lock.acquire() self.is_computing = False self.is_waiting = True self.status_lock.release() continue else: self.status_lock.release() continue self.data_lock.acquire() if len(self.unprocessed_sky) > 0: self.step += 1 self.process_skyline() # write out data from the final round self.write_out_skyline() self.data_lock.release() except (SystemExit, KeyboardInterrupt) as exp: logger.debug("Received keyboard interrupt") raise(exp) except Exception: # self.status_lock.release() # traceback.print_exc() logger.exception("Encountered problem in backend") self.is_running = False # when we get here, we are done! self.output.close() logger.info("Ending run loop")
class Worker(): def __init__(self, infile, master, process_line=None, work_id=None): self.infile = infile self.inputf = open(infile, 'r') self.master_url = master if work_id is not None: self.worker_id = work_id else: self.worker_id = create_nonce(10) handler = logging.StreamHandler(stream=sys.stdout) # logger = logging.FileHandler("worker-{}.log".format(self.worker_id)) formatter = logging.Formatter("%(asctime)s: %(levelname)s: %(name)s: " "%(message)s") self.logger = logging.getLogger(self.worker_id) self.logger.setLevel(logging.DEBUG) handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) self.logger.addHandler(handler) # logging.getLogger('').addHandler(logger) # logging.getLogger('').setLevel(logging.DEBUG) # self.logger = logging.getLogger(self.worker_id) self.process_line = json.loads if process_line is not None: self.process_line = process_line # verify that we can actually talk to the master by trying to # get information about the step size self.verify_master() # create the skyline stuff self.sky = Skyline() self.old_skys = {} def verify_master(self): """Verify the location of the master and get the time step and size """ req = requests.get(self.master_url + "/step", timeout=SERVER_TIMEOUT) req.raise_for_status() entry = req.json() self.step = entry['step'] self.step_size = entry['step_size'] self.win_size = entry['step_window'] self.start_time = entry['start_time'] self.window_start = entry['window_time'] self.window_end = self.window_start + self.step_size self.logger.info("Checked in with the master and got {}".format(entry)) def run(self): """Method to read in the streaming entries, process the skyline, and send results to the master """ print ("Worker is now running at step {} with step_size {} starting " "at time {}".format(self.step, self.step_size, self.start_time)) # read in the entries for this step processed, last_proc = 0, 0 if RECORD_ALL: self.sky_size = open('skyline-size.json', 'w') self.sky.comp_size = open('sky-comp-size.json', 'w') self.sky.sky_file = open('sky-file.json', 'w') for line in self.inputf.xreadlines(): entry = self.process_line(line) processed += 1 last_proc += 1 if (processed % 1000) == 0: self.logger.info("Processed {} total entries ({} after last " "step)".format(processed, last_proc)) # write out skyline size if necessary if RECORD_ALL: item = {'time': time.time(), 'num_entry': processed, 'sky_size': self.sky.skyline.qsize()} self.sky_size.write(json.dumps(item) + "\n") self.sky_size.flush() # if we are moving beyond this timestep, then wait for # more data from the master if entry['step'] > self.step: self.upload_data() self.logger.debug("Starting to wait on upload for {}" "".format(UPLOAD_WAIT)) time.sleep(UPLOAD_WAIT) self.get_master_updates() last_proc = 0 # now update the skyline using this point self.update_skyline(entry) self.inputf.close() if RECORD_ALL: self.sky_size.close() self.sky.comp_size.close() self.sky.sky_file.close() self.upload_data() req = requests.get(self.master_url + "/worker_done") req.raise_for_status() def upload_data(self): """Upload the changes to the skyline to the master node We will perform the following activities here: 1) find difference in old and new skyline (skyline updates to send to master) 2) send data to master """ self.logger.debug("Starting to upload data") # find the difference in old and new skyline (skyline updates # to send to master added, removed = self.find_skyline_diff() url = self.master_url + "/update_master" headers = {'content-type': 'application/json'} params = {'worker_id': self.worker_id} upload_data = {'step': self.step, 'added': added, 'removed': removed, 'worker_id': self.worker_id} self.logger.debug("Preparing to upload: {}".format(upload_data)) # upload the data, but make sure that we try several times on failure for x in range(SERVER_REQUERIES): req = requests.post(url, timeout=SERVER_TIMEOUT, headers=headers, data=json.dumps(upload_data), params=params) # self.logger.debug("Sent upload data to {}".format(url)) if req.status_code == 200: break # wait a few seconds before retrying time.sleep(SERVER_TIMEOUT) # ensure that we actually uploaded successfully req.raise_for_status() def find_skyline_diff(self): # first compute the new skyline's set skys = {} to_see = self.sky.skyline.qsize() # while not self.sky.skyline.empty(): for x in range(to_see): item = self.sky.skyline.get_nowait() step = tuple([item['step']]) key = tuple(item['data']) + step skys[key] = item self.sky.skyline.put(item) new_keys = set(skys.keys()) old_keys = set(self.old_skys.keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: self.old_skys[x], removed) self.logger.debug("Skyline diff- added: {} removed: {}" "".format(added, removed)) return added, removed def get_master_updates(self): """Update the local skyline based on points from the master/central node's skyline To get the skyline, we will query the master server a total of WORKER_REQUERIES times and wait WORKER_MASTER_WAIT seconds before declaring failure/ raising an exception We will perform the following activities here 1) update local skyline based on master updates 2) expire old points """ self.logger.debug("Starting to get master updates") params = {'worker_id': self.worker_id} for x in range(WORKER_REQUERIES): url = "{}/get_skyline/{}".format(self.master_url, self.step) req = requests.get(url, timeout=SERVER_TIMEOUT, params=params) # if we got a successful response, then let's break out if req.status_code == 200: break # if currently computing or waiting for other nodes, then # wait longer elif req.status_code == 423: self.logger.debug("Received wait command from master when " "starting update from master") time.sleep(WORKER_MASTER_WAIT) # otherwise, just break out now with an error else: req.raise_for_status() data = req.json() self.logger.debug("Receieved master update: {}".format(data)) self.step += 1 # handle the removals and additions in a single pass to_remove, old_skys = {}, {} for point in data['removed']: to_remove[tuple(point['data'])] = point to_see = self.sky.skyline.qsize() for idx in range(to_see): point = self.sky.skyline.get_nowait() if tuple(point['data']) in to_remove: continue self.sky.skyline.put(point) step = tuple([point['step']]) old_skys[tuple(point['data']) + step] = point for point in data['added']: self.sky.skyline.put(point) step = tuple([point['step']]) old_skys[tuple(point['data']) + step] = point # now that we have the global skyline from the previous # timestep, let's create a datastructure to snapshot what we # will later add and remove self.old_skys = old_skys # expire points from the skyline self.expire_points() def expire_points(self): """Expire old points from the skyline""" self.logger.debug("Starting to expire points for step {}" "(anything less than {})" "".format(self.step, self.step - self.win_size)) has_expired = False to_see = self.sky.skyline.qsize() # while not self.sky.skyline.empty(): for x in range(to_see): item = self.sky.skyline.get_nowait() if item['step'] <= (self.step - self.win_size): has_expired = True # self.logger.debug("Expiring point {} at step {}" # "".format(item, self.step)) else: self.sky.skyline.put(item) # if we have not expired any skyline points, then we don't # need to check the non-skyline points and we are done if not has_expired: # self.logger.debug("No expiration points found") return # rerun and expire all of the non-skyline points in a single # check to_see = self.sky.non_sky.qsize() # while not self.sky.non_sky.empty(): for x in range(to_see): item = self.sky.non_sky.get_nowait() # self.logger.debug("testing non sky point: {}".format(item)) if item['step'] <= (self.step - self.win_size): has_expired = True else: self.update_skyline(item) def update_skyline(self, point): """Update the local skyline based on this point Note: when the skyline changes, we also need to update self.skyline_updates because that is what will be sent to the master """ added = self.sky.update_sky_for_point(point) return added
class Worker(): def __init__(self, infile, master, process_line=None, work_id=None): self.infile = infile self.inputf = open(infile, 'r') self.master_url = master if work_id is not None: self.worker_id = work_id else: self.worker_id = create_nonce(10) handler = logging.StreamHandler(stream=sys.stdout) # logger = logging.FileHandler("worker-{}.log".format(self.worker_id)) formatter = logging.Formatter("%(asctime)s: %(levelname)s: %(name)s: " "%(message)s") self.logger = logging.getLogger(self.worker_id) self.logger.setLevel(logging.DEBUG) handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) self.logger.addHandler(handler) # logging.getLogger('').addHandler(logger) # logging.getLogger('').setLevel(logging.DEBUG) # self.logger = logging.getLogger(self.worker_id) self.process_line = json.loads if process_line is not None: self.process_line = process_line # verify that we can actually talk to the master by trying to # get information about the step size self.verify_master() # create the skyline stuff self.sky = Skyline() self.old_skys = {} def verify_master(self): """Verify the location of the master and get the time step and size """ req = requests.get(self.master_url + "/step", timeout=SERVER_TIMEOUT) req.raise_for_status() entry = req.json() self.step = entry['step'] self.step_size = entry['step_size'] self.win_size = entry['step_window'] self.start_time = entry['start_time'] self.window_start = entry['window_time'] self.window_end = self.window_start + self.step_size self.logger.info("Checked in with the master and got {}".format(entry)) def run(self): """Method to read in the streaming entries, process the skyline, and send results to the master """ print("Worker is now running at step {} with step_size {} starting " "at time {}".format(self.step, self.step_size, self.start_time)) # read in the entries for this step processed, last_proc = 0, 0 if RECORD_ALL: self.sky_size = open('skyline-size.json', 'w') self.sky.comp_size = open('sky-comp-size.json', 'w') self.sky.sky_file = open('sky-file.json', 'w') for line in self.inputf.xreadlines(): entry = self.process_line(line) processed += 1 last_proc += 1 if (processed % 1000) == 0: self.logger.info("Processed {} total entries ({} after last " "step)".format(processed, last_proc)) # write out skyline size if necessary if RECORD_ALL: item = { 'time': time.time(), 'num_entry': processed, 'sky_size': self.sky.skyline.qsize() } self.sky_size.write(json.dumps(item) + "\n") self.sky_size.flush() # if we are moving beyond this timestep, then wait for # more data from the master if entry['step'] > self.step: self.upload_data() self.logger.debug("Starting to wait on upload for {}" "".format(UPLOAD_WAIT)) time.sleep(UPLOAD_WAIT) self.get_master_updates() last_proc = 0 # now update the skyline using this point self.update_skyline(entry) self.inputf.close() if RECORD_ALL: self.sky_size.close() self.sky.comp_size.close() self.sky.sky_file.close() self.upload_data() req = requests.get(self.master_url + "/worker_done") req.raise_for_status() def upload_data(self): """Upload the changes to the skyline to the master node We will perform the following activities here: 1) find difference in old and new skyline (skyline updates to send to master) 2) send data to master """ self.logger.debug("Starting to upload data") # find the difference in old and new skyline (skyline updates # to send to master added, removed = self.find_skyline_diff() url = self.master_url + "/update_master" headers = {'content-type': 'application/json'} params = {'worker_id': self.worker_id} upload_data = { 'step': self.step, 'added': added, 'removed': removed, 'worker_id': self.worker_id } self.logger.debug("Preparing to upload: {}".format(upload_data)) # upload the data, but make sure that we try several times on failure for x in range(SERVER_REQUERIES): req = requests.post(url, timeout=SERVER_TIMEOUT, headers=headers, data=json.dumps(upload_data), params=params) # self.logger.debug("Sent upload data to {}".format(url)) if req.status_code == 200: break # wait a few seconds before retrying time.sleep(SERVER_TIMEOUT) # ensure that we actually uploaded successfully req.raise_for_status() def find_skyline_diff(self): # first compute the new skyline's set skys = {} to_see = self.sky.skyline.qsize() # while not self.sky.skyline.empty(): for x in range(to_see): item = self.sky.skyline.get_nowait() step = tuple([item['step']]) key = tuple(item['data']) + step skys[key] = item self.sky.skyline.put(item) new_keys = set(skys.keys()) old_keys = set(self.old_skys.keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: self.old_skys[x], removed) self.logger.debug("Skyline diff- added: {} removed: {}" "".format(added, removed)) return added, removed def get_master_updates(self): """Update the local skyline based on points from the master/central node's skyline To get the skyline, we will query the master server a total of WORKER_REQUERIES times and wait WORKER_MASTER_WAIT seconds before declaring failure/ raising an exception We will perform the following activities here 1) update local skyline based on master updates 2) expire old points """ self.logger.debug("Starting to get master updates") params = {'worker_id': self.worker_id} for x in range(WORKER_REQUERIES): url = "{}/get_skyline/{}".format(self.master_url, self.step) req = requests.get(url, timeout=SERVER_TIMEOUT, params=params) # if we got a successful response, then let's break out if req.status_code == 200: break # if currently computing or waiting for other nodes, then # wait longer elif req.status_code == 423: self.logger.debug("Received wait command from master when " "starting update from master") time.sleep(WORKER_MASTER_WAIT) # otherwise, just break out now with an error else: req.raise_for_status() data = req.json() self.logger.debug("Receieved master update: {}".format(data)) self.step += 1 # handle the removals and additions in a single pass to_remove, old_skys = {}, {} for point in data['removed']: to_remove[tuple(point['data'])] = point to_see = self.sky.skyline.qsize() for idx in range(to_see): point = self.sky.skyline.get_nowait() if tuple(point['data']) in to_remove: continue self.sky.skyline.put(point) step = tuple([point['step']]) old_skys[tuple(point['data']) + step] = point for point in data['added']: self.sky.skyline.put(point) step = tuple([point['step']]) old_skys[tuple(point['data']) + step] = point # now that we have the global skyline from the previous # timestep, let's create a datastructure to snapshot what we # will later add and remove self.old_skys = old_skys # expire points from the skyline self.expire_points() def expire_points(self): """Expire old points from the skyline""" self.logger.debug("Starting to expire points for step {}" "(anything less than {})" "".format(self.step, self.step - self.win_size)) has_expired = False to_see = self.sky.skyline.qsize() # while not self.sky.skyline.empty(): for x in range(to_see): item = self.sky.skyline.get_nowait() if item['step'] <= (self.step - self.win_size): has_expired = True # self.logger.debug("Expiring point {} at step {}" # "".format(item, self.step)) else: self.sky.skyline.put(item) # if we have not expired any skyline points, then we don't # need to check the non-skyline points and we are done if not has_expired: # self.logger.debug("No expiration points found") return # rerun and expire all of the non-skyline points in a single # check to_see = self.sky.non_sky.qsize() # while not self.sky.non_sky.empty(): for x in range(to_see): item = self.sky.non_sky.get_nowait() # self.logger.debug("testing non sky point: {}".format(item)) if item['step'] <= (self.step - self.win_size): has_expired = True else: self.update_skyline(item) def update_skyline(self, point): """Update the local skyline based on this point Note: when the skyline changes, we also need to update self.skyline_updates because that is what will be sent to the master """ added = self.sky.update_sky_for_point(point) return added
def process_skyline(self): """Script to process the skyline for each new data point There are 2 phases to this: 1) update the individual skyline 2) update the global skyline from the individuals """ work_seen = {} global_seen = {} try: # update each local skyline for sky in self.unprocessed_sky: worker = sky['worker_id'] added, removed = sky['added'], sky['removed'] work_seen[worker] = {} logger.debug("starting to process: {} {} {}" "".format(worker, added, removed)) # add and remove the entries if worker not in self.skylines: self.skylines[worker] = Queue.Queue() # remove the entries we don't need # remove logger.debug("here 1") to_see = self.skylines[worker].qsize() for idx in range(to_see): # remove logger.debug("removing") item = self.skylines[worker].get_nowait() if item in removed: logger.debug("{} in removed".format(item)) continue self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item # and add the new entries # remove logger.debug("here 2") for item in added: # remove logger.debug("adding") self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item logger.debug("skylines: {}".format(work_seen)) # self.step = item['step'] # remove logger.debug("here 3") # now update the global skyline based on the items self.sky = Skyline() for key in global_seen: # remove logger.debug("updating point {}".format(item)) item = global_seen[key] self.sky.update_sky_for_point(item) # snapshot the global skyline skys = {} self.skyline = [] to_see = self.sky.skyline.qsize() for x in range(to_see): item = self.sky.skyline.get_nowait() key = tuple(item['data'] + [item['step']]) skys[key] = item self.sky.skyline.put(item) # remove logger.debug("skyline point {}".format(item)) self.skyline.append(item) new_keys = set(skys.keys()) logger.debug("Global skyline is: {}".format(self.skyline)) # return the difference to each worker for worker in work_seen: old_keys = set(work_seen[worker].keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: work_seen[worker][x], removed) update = {'step': self.step, 'added': added, 'removed': removed, 'worker_id': worker} self.skyline_changes[worker] = update logger.debug("skyline changes {}".format(update)) self.unprocessed_sky = [] self.recv_workers = {} self.sky_received = 0 except (SystemExit, KeyboardInterrupt) as exp: logger.info("Received keyboard interrupt") raise(exp) except Exception: # traceback.print_exc() logger.exception("problem in processing skyline")
def visitSkyline(self, ctx: SkylineParser.SkylineContext) -> Skyline: nodes = [w for w in ctx.children] if ctx.mirror(): skln = Skyline(self.visit(nodes[1])) skln.invert() return skln if ctx.translate_r(): skln = Skyline(self.visit(nodes[0])) offset = int(nodes[2].getText()) skln.translate(offset) return skln if ctx.translate_l(): skln = Skyline(self.visit(nodes[0])) offset = -int(nodes[2].getText()) skln.translate(offset) return skln if ctx.replicate(): skln = Skyline(self.visit(nodes[0])) n = int(nodes[2].getText()) skln.replicate(n) return skln if ctx.union(): skln1: Skyline = self.visit(nodes[0]) skln2: Skyline = self.visit(nodes[2]) skln = skln1.clone() skln.union(skln2) return skln if ctx.intersection(): skln1: Skyline = self.visit(nodes[0]) skln2: Skyline = self.visit(nodes[2]) skln = skln1.clone() skln.intersection(skln2) return skln if ctx.existing_skyline(): name: str = nodes[0].getText() skln = self.user_skylines[name] if skln is None: print("Skyline inexistente!!") return skln if ctx.random_skyline(): return self.visit(nodes[1]) if ctx.building_list(): skln: Skyline = Skyline() buildings = self.visit(nodes[1]) skln.insert_buildings(buildings) return skln if ctx.building(): (xmin, h, xmax) = self.visit(nodes[1]) if xmax <= xmin: print("Invalid x-coord range!!") return Skyline() if h < 1: print("Invalid height!!") return Skyline() return Skyline(xmin, h, xmax) # Between brackets skyline return self.visit(nodes[1])
def visitCompost(self, ctx: SkylineParser.CompostContext): eds = self.visit(ctx.getChild(1)) return Skyline(eds)
class Master(): def __init__(self, outfile, start_time, step_size, win_size, num_workers=2, workers=None): logger.info("Created master class") self.outfile = outfile self.num_workers = num_workers self.non_skyline = [] self.sky_received = 0 self.unprocessed_sky = [] self.recv_workers = {} self.start_time = start_time self.window_time = start_time self.win_size = win_size self.step = 0 self.step_size = step_size self.last_received_time = time.time() self.is_running = False self.is_waiting = False self.is_computing = False self.have_new_data = False self.status_lock = threading.Lock() self.data_lock = threading.Lock() self.sky = Skyline() self.skyline = [] self.skylines = {} self.skyline_changes = {} def process_skyline(self): """Script to process the skyline for each new data point There are 2 phases to this: 1) update the individual skyline 2) update the global skyline from the individuals """ work_seen = {} global_seen = {} try: # update each local skyline for sky in self.unprocessed_sky: worker = sky['worker_id'] added, removed = sky['added'], sky['removed'] work_seen[worker] = {} logger.debug("starting to process: {} {} {}" "".format(worker, added, removed)) # add and remove the entries if worker not in self.skylines: self.skylines[worker] = Queue.Queue() # remove the entries we don't need # remove logger.debug("here 1") to_see = self.skylines[worker].qsize() for idx in range(to_see): # remove logger.debug("removing") item = self.skylines[worker].get_nowait() if item in removed: logger.debug("{} in removed".format(item)) continue self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item # and add the new entries # remove logger.debug("here 2") for item in added: # remove logger.debug("adding") self.skylines[worker].put(item) key = tuple(item['data'] + [item['step']]) work_seen[worker][key] = item global_seen[key] = item logger.debug("skylines: {}".format(work_seen)) # self.step = item['step'] # remove logger.debug("here 3") # now update the global skyline based on the items self.sky = Skyline() for key in global_seen: # remove logger.debug("updating point {}".format(item)) item = global_seen[key] self.sky.update_sky_for_point(item) # snapshot the global skyline skys = {} self.skyline = [] to_see = self.sky.skyline.qsize() for x in range(to_see): item = self.sky.skyline.get_nowait() key = tuple(item['data'] + [item['step']]) skys[key] = item self.sky.skyline.put(item) # remove logger.debug("skyline point {}".format(item)) self.skyline.append(item) new_keys = set(skys.keys()) logger.debug("Global skyline is: {}".format(self.skyline)) # return the difference to each worker for worker in work_seen: old_keys = set(work_seen[worker].keys()) added = new_keys - old_keys removed = old_keys - new_keys added = map(lambda x: skys[x], added) removed = map(lambda x: work_seen[worker][x], removed) update = { 'step': self.step, 'added': added, 'removed': removed, 'worker_id': worker } self.skyline_changes[worker] = update logger.debug("skyline changes {}".format(update)) self.unprocessed_sky = [] self.recv_workers = {} self.sky_received = 0 except (SystemExit, KeyboardInterrupt) as exp: logger.info("Received keyboard interrupt") raise (exp) except Exception: # traceback.print_exc() logger.exception("problem in processing skyline") def write_out_skyline(self): logger.info("Writing out skyline") entry = {'step': self.step - 1, 'data': self.skyline} self.output.write(json.dumps(entry) + "\n") def run_loop(self): # open output file self.output = open(self.outfile, 'w') # initialize our variables self.status_lock.acquire() self.is_running = True self.is_waiting = True self.is_computing = False self.step = 0 self.window_time = self.start_time self.status_lock.release() logger.info("Starting background thread loop") # the main run loop will see if the web server has brought us # any goodies, then run the skyline if possible or preempt for # a few seconds until we can keep_running = True try: while keep_running: self.status_lock.acquire() # logger.debug("running: {}".format(keep_running)) # if we are out of workers, then quit if self.num_workers <= 0: logger.info("Out of workers, so quitting") self.status_lock.release() keep_running = False continue # if we don't have anything new, preempt until we have # something. If we have waited more than the timeout # period, then end # if not self.have_new_data: if self.sky_received != self.num_workers: time_since_update = time.time() - self.last_received_time if (time_since_update > MASTER_TIMEOUT_TO_END): logger.info("Didn't receive anything in the " "timeout, so ending") self.status_lock.release() keep_running = False continue self.status_lock.release() logger.debug("waiting for new data") time.sleep(MASTER_WAIT_TIME) continue # check how many workers have given us the skyline for # this timestep to determine if we can compute the # skyline if self.sky_received == self.num_workers: logger.debug("Received data from all workers, so " "starting to compute") self.waiting = False self.is_computing = True self.sky_received = 0 self.step += 1 time_elapsed = (self.step * self.step_size) self.window_time = self.start_time + time_elapsed self.status_lock.release() self.data_lock.acquire() self.process_skyline() # now that we have finished a round, write out the # data and increment the step self.write_out_skyline() self.data_lock.release() self.status_lock.acquire() self.is_computing = False self.is_waiting = True self.status_lock.release() continue else: self.status_lock.release() continue self.data_lock.acquire() if len(self.unprocessed_sky) > 0: self.step += 1 self.process_skyline() # write out data from the final round self.write_out_skyline() self.data_lock.release() except (SystemExit, KeyboardInterrupt) as exp: logger.debug("Received keyboard interrupt") raise (exp) except Exception: # self.status_lock.release() # traceback.print_exc() logger.exception("Encountered problem in backend") self.is_running = False # when we get here, we are done! self.output.close() logger.info("Ending run loop")
def main(): irc = IRC() irc.connect(config.HOST, config.PORT, config.CHANNEL, config.NICK) skyline = Skyline(config.BRIDGE_IP) skyline.start() stream_room = Group('Stream Room', lights=[ 'Roo side table', 'Lunar side table', 'Desk Portrait Left', 'Desk Portrait Right' ]) _thread.start_new_thread(irc.fill_user_list, ()) while True: response = irc.receive() # If Twitch pings the bot, respond. irc.respond_to_ping(response) username, message = irc.parse_message(response) # Custom commands insta_com = Command('insta', response='Follow r00 on Instagram at www.instagram.com/user_r00') twitter_com = Command('twitter', response='Follow r00 on Twitter at www.twitter.com/user_r00') ping_com = Command('ping', response='Pong') lights_com = Command('lights', response='Control r00\'s lighting with !lights and a color. For example, "!lights purple" will set the room lights to purple! For a full list of colors use !lightcolors.') # irc.process_command(response) if message.strip() == '!ping': irc.chat(ping_com.response) # Socials if message.strip() == "!insta": irc.chat(insta_com.response) elif message.strip() == '!twitter': irc.chat(twitter_com.response) # Shoutouts elif message.strip().split(' ')[0] == "!so": streamer_long = message.strip().split(' ')[1] streamer_short = streamer_long.replace('@', '') irc.chat(f'If you\'re looking for more interesting content, ' f'go check out {streamer_long} at ' f'https://twitch.tv/{streamer_short} ! Drop them a ' f'follow to be notified when they go live.') elif message.strip() == '!crash': # Get a light and collect its current colors for later. light = skyline.lights['Roo side table'] hue, sat, bri = light.hue, light.saturation, light.brightness # Create temporary light to hold current settings. temp_color = Color('temp', hue=hue, sat=sat, bri=bri) skyline.set_color(stream_room.lights, 'red') sleep(3) skyline.set_color(stream_room.lights, temp_color) # Skyline elif message.strip() == '!lights': irc.chat(lights_com.response) elif message.strip() == '!lightcolors': message = 'Lights can be set to ' counter = 0 for color in skyline.colors: if counter < len(skyline.colors.keys()) - 1: message = f'{message}{skyline.colors[color].name}, ' counter += 1 else: message = f'{message} or {skyline.colors[color].name}.' irc.chat(message) elif message.strip().split(' ')[0] == "!lights": color = message.strip().split(' ')[1] if color in skyline.colors: skyline.set_color(stream_room.lights, color) else: irc.chat('Honestly, I have no idea what you want.') elif message.strip() == '!rainbow': skyline.rainbow(stream_room.lights) sleep(1)
def visitTemp_skyline(self, ctx: SkylineParser.Temp_skylineContext): nodes = [w for w in ctx.children] new_skyline = Skyline(self.visit(nodes[0])) return new_skyline
def visitSimple(self, ctx: SkylineParser.SimpleContext): ed = self.visit(ctx.getChild(0)) return Skyline([ed])