Esempio n. 1
0
    def test_check_song_for_conflict(self):
        db.c.update("DELETE FROM r4_listeners")
        db.c.update("DELETE FROM r4_request_store")

        e = Election.create(1)
        self.assertEqual(False, e._check_song_for_conflict(self.song1))

        u = User(2)
        u.authorize(sid=1, ip_address=None, api_key=None, bypass=True)
        self.assertEqual(1, u.put_in_request_line(1))
        # TODO: Use proper request/user methods here instead of DB call
        db.c.update(
            "UPDATE r4_request_line SET line_top_song_id = %s, line_expiry_tune_in = %s WHERE user_id = %s",
            (self.song1.id, int(time.time()) + 9999, u.id))
        db.c.update(
            "INSERT INTO r4_listeners (sid, user_id, listener_icecast_id) VALUES (1, %s, 1)",
            (u.id, ))
        db.c.update(
            "INSERT INTO r4_request_store (user_id, song_id, sid) VALUES (%s, %s, 1)",
            (u.id, self.song1.id))
        request.update_cache(1)
        request.update_expire_times()
        cache.update_local_cache_for_sid(1)
        self.assertEqual(True, e._check_song_for_conflict(self.song1))
        self.assertEqual(True, e._check_song_for_conflict(self.song5))
        self.assertEqual(event.ElecSongTypes.conflict,
                         self.song5.data['entry_type'])
        self.assertEqual(event.ElecSongTypes.request,
                         self.song1.data['entry_type'])
Esempio n. 2
0
def post_process(sid):
	try:
		db.c.start_transaction()
		start_time = time.time()
		playlist.prepare_cooldown_algorithm(sid)
		rainwave.playlist_objects.album.clear_updated_albums(sid)
		log.debug("post", "Playlist prepare time: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		current[sid].finish()
		log.debug("post", "Current finish time: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		last_song = current[sid].get_song()
		if last_song:
			db.c.update("INSERT INTO r4_song_history (sid, song_id) VALUES (%s, %s)", (sid, last_song.id))
		log.debug("post", "Last song insertion time: %s" % (time.time() - start_time,))

		start_time = time.time()
		history[sid].insert(0, current[sid])
		while len(history[sid]) > 5:
			history[sid].pop()
		log.debug("post", "History management: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		current[sid] = upnext[sid].pop(0)
		current[sid].start_event()
		log.debug("advance", "Current management: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		playlist.warm_cooled_songs(sid)
		playlist.warm_cooled_albums(sid)
		log.debug("advance", "Cooldown warming: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		_add_listener_count_record(sid)
		_trim(sid)
		user.trim_listeners(sid)
		cache.update_user_rating_acl(sid, history[sid][0].get_song().id)
		user.unlock_listeners(sid)
		log.debug("advance", "User management and trimming: %.6f" % (time.time() - start_time,))

		start_time = time.time()
		# reduce song blocks has to come first, otherwise it wll reduce blocks generated by _create_elections
		playlist.reduce_song_blocks(sid)
		# update_cache updates both the line and expiry times
		# this is expensive and not necessary to do more than once
		# DO THIS AFTER EVERYTHING ELSE, RIGHT BEFORE NEXT MANAGEMENT, OR PEOPLE'S REQUESTS SLIP THROUGH THE CRACKS
		request.update_cache(sid)
		# add to the event list / update start times for events
		manage_next(sid)
		log.debug("advance", "Request and upnext management: %.6f" % (time.time() - start_time,))

		update_memcache(sid)
		sync_to_front.sync_frontend_all(sid)
		db.c.commit()
	except:
		db.c.rollback()
		raise
Esempio n. 3
0
	def test_check_song_for_conflict(self):
		db.c.update("DELETE FROM r4_listeners")
		db.c.update("DELETE FROM r4_request_store")
	
		e = Election.create(1)
		self.assertEqual(False, e._check_song_for_conflict(self.song1))
		
		u = User(2)
		u.authorize(1, None, None, True)
		self.assertEqual(1, u.put_in_request_line(1))
		# TODO: Use proper request/user methods here instead of DB call
		db.c.update("UPDATE r4_request_line SET line_top_song_id = %s, line_expiry_tune_in = %s WHERE user_id = %s", (self.song1.id, time.time()+9999, u.id))
		db.c.update("INSERT INTO r4_listeners (sid, user_id, listener_icecast_id) VALUES (1, %s, 1)", (u.id,))
		db.c.update("INSERT INTO r4_request_store (user_id, song_id, sid) VALUES (%s, %s, 1)", (u.id, self.song1.id))
		request.update_cache(1)
		cache.update_local_cache_for_sid(1)
		self.assertEqual(True, e._check_song_for_conflict(self.song1))
		self.assertEqual(False, e._check_song_for_conflict(self.song5))
		self.assertEqual(event.ElecSongTypes.conflict, self.song5.data['entry_type'])
		self.assertEqual(event.ElecSongTypes.request, self.song1.data['entry_type'])
Esempio n. 4
0
def _create_elections(sid):
    # Step, er, 0: Update the request cache first, so elections have the most recent data to work with
    # (the entire requests module depends on its caches)
    request.update_cache(sid)

    max_sched_id, max_elec_id, num_elections = _get_schedule_stats(sid)
    log.debug(
        "create_elec",
        "Max sched ID: %s // Max elec ID: %s // Num elections already existing: %s // Size of next: %s"
        % (max_sched_id, max_elec_id, num_elections, len(next[sid])))

    # Step 2: Load up any elections that have been added while we've been idle and append them to the list
    unused_elec_id = db.c.fetch_list(
        "SELECT elec_id FROM r4_elections WHERE sid = %s AND elec_id > %s AND elec_used = FALSE AND elec_priority = FALSE ORDER BY elec_id",
        (sid, max_elec_id))
    unused_elecs = []
    for elec_id in unused_elec_id:
        unused_elecs.append(event.Election.load_by_id(elec_id))

    # Step 3: Insert elections where there's time and adjust predicted start times as necessary, if num_elections < 2 then create them where necessary
    i = 1
    running_time = current[sid].start_actual + current[sid].length()
    if len(next[sid]) > 0:
        next[sid][0].start = running_time
    while i < len(next[sid]):
        next_start = next[sid][i].start
        gap = next_start - running_time
        next_elec_i = None
        next_elec_length = playlist.get_average_song_length(sid)
        j = i
        while j < len(next[sid]):
            if next[sid][j].is_election:
                next_elec = j
                next_elec_length = next[sid][j].length()
                break
        if not next_elec_i and len(unused_elecs) > 0:
            next_elec_length = unused_elecs[0].length()

        # TODO: This algorithm DEFINITELY needs code/concept review
        # There are potential holes - it is not as comprehensive a scheduler as the previous
        # Rainwave scheduler, however it is vastly simplified.
        # One drawback is that you cannot schedule elections themselves to run at certain times.

        create_elecs = False
        # If the event we're looking at collides with the previous event, adjust this event to start later
        if gap <= 0:
            next[sid][i].start = running_time
            running_time += next[sid][i].length()
        # If we have no elections current in the next list and there's enough time to fit a song, stuff an election in
        # (this automatically takes into account unused elections, based on next_elec_length definition above)
        elif not next_elec_i and gap <= (next_elec_length * 1.4):
            next_elec = None
            # If we have an existing unused election, we can use that (as next_elec_length is already based on the first unused elec, this can happen)
            if len(unused_elecs) > 0:
                next_elec = unused_elecs.pop(0)
            # If not, create a new election timed to the gap (next_elec_length will be the average song length*1.4, so this will happen frequently)
            else:
                next_elec = _create_election(sid, running_time, gap)
            num_elections += 1
            next_elec.start = running_time
            running_time += next_elec.length()
            next[sid].insert(i, next_elec)
        # If it's more accurate to squeeze a created election in here than adjust the next event, move the event
        # *OR* the next event is too far out and we have elections in hand
        elif next_elec_i and ((gap <= (next_elec_length / 2)) or
                              (gap > (next_elec_length * 1.5))):
            next_elec = next[sid].pop(next_elec_i)
            next_elec.start = running_time
            running_time += next_elec.length()
            next[sid].insert(i, next_elec)
        # The next event is better off aligned
        else:
            next[sid][i].start = running_time
            running_time += next[sid][i].length()
        i += 1

    needed_elecs = config.get_station(sid,
                                      "num_planned_elections") - num_elections
    log.debug(
        "create_elec",
        "Before: Needed elecs: %s // Unused elecs: %s // Current num elections: %s // Next size: %s"
        % (needed_elecs, len(unused_elecs), num_elections, len(next[sid])))
    # Step 5: If we're at less than X elections available, create them (or use unused ones) and append them
    # No timing is required here, since we're simply outright appending to the end
    # (any elections appearing before a scheduled item would be handled by the block above)
    failures = 0
    while needed_elecs > 0 and failures <= 2:
        next_elec = None
        if len(unused_elecs) > 0:
            next_elec = unused_elecs.pop(0)
        else:
            next_elec = _create_election(sid, running_time)
        next_elec_length = next_elec.length()
        if next_elec_length > 0:
            next_elec.start = running_time
            running_time += next_elec.length()
            next[sid].append(next_elec)
            num_elections += 1
            needed_elecs -= 1
        else:
            log.error("create_elec",
                      "Election ID %s was faulty - zero length.  Deleting.")
            next_elec.delete()
            failures += 1
    if failures >= 2:
        log.error("create_elec", "Total failure when creating elections.")
    log.debug(
        "create_elec",
        "After: Unused elecs: %s // Current num elections: %s // Next size: %s"
        % (len(unused_elecs), num_elections, len(next[sid])))
Esempio n. 5
0
def post_process(sid):
    try:
        db.c.start_transaction()
        start_time = time.time()
        playlist.prepare_cooldown_algorithm(sid)
        rainwave.playlist_objects.album.clear_updated_albums(sid)
        log.debug("post",
                  "Playlist prepare time: %.6f" % (time.time() - start_time, ))

        start_time = time.time()
        current[sid].finish()
        log.debug("post",
                  "Current finish time: %.6f" % (time.time() - start_time, ))

        start_time = time.time()
        last_song = current[sid].get_song()
        if last_song:
            db.c.update(
                "INSERT INTO r4_song_history (sid, song_id) VALUES (%s, %s)",
                (sid, last_song.id))
        log.debug(
            "post",
            "Last song insertion time: %s" % (time.time() - start_time, ))

        start_time = time.time()
        history[sid].insert(0, current[sid])
        while len(history[sid]) > 5:
            history[sid].pop()
        log.debug("post",
                  "History management: %.6f" % (time.time() - start_time, ))

        start_time = time.time()
        current[sid] = upnext[sid].pop(0)
        current[sid].start_event()
        log.debug("advance",
                  "Current management: %.6f" % (time.time() - start_time, ))

        start_time = time.time()
        playlist.warm_cooled_songs(sid)
        playlist.warm_cooled_albums(sid)
        log.debug("advance",
                  "Cooldown warming: %.6f" % (time.time() - start_time, ))

        start_time = time.time()
        _add_listener_count_record(sid)
        _trim(sid)
        user.trim_listeners(sid)
        cache.update_user_rating_acl(sid, history[sid][0].get_song().id)
        user.unlock_listeners(sid)
        log.debug(
            "advance", "User management and trimming: %.6f" %
            (time.time() - start_time, ))

        start_time = time.time()
        # reduce song blocks has to come first, otherwise it wll reduce blocks generated by _create_elections
        playlist.reduce_song_blocks(sid)
        # update_cache updates both the line and expiry times
        # this is expensive and not necessary to do more than once
        # DO THIS AFTER EVERYTHING ELSE, RIGHT BEFORE NEXT MANAGEMENT, OR PEOPLE'S REQUESTS SLIP THROUGH THE CRACKS
        request.update_cache(sid)
        # add to the event list / update start times for events
        manage_next(sid)
        log.debug(
            "advance", "Request and upnext management: %.6f" %
            (time.time() - start_time, ))

        update_memcache(sid)
        sync_to_front.sync_frontend_all(sid)
        db.c.commit()
    except:
        db.c.rollback()
        raise
Esempio n. 6
0
def _create_elections(sid):
	# Step, er, 0: Update the request cache first, so elections have the most recent data to work with
	# (the entire requests module depends on its caches)
	request.update_cache(sid)

	max_sched_id, max_elec_id, num_elections = _get_schedule_stats(sid)
	log.debug("create_elec", "Max sched ID: %s // Max elec ID: %s // Num elections already existing: %s // Size of next: %s" % (max_sched_id, max_elec_id, num_elections, len(next[sid])))

	# Step 2: Load up any elections that have been added while we've been idle and append them to the list
	unused_elec_id = db.c.fetch_list("SELECT elec_id FROM r4_elections WHERE sid = %s AND elec_id > %s AND elec_used = FALSE AND elec_priority = FALSE ORDER BY elec_id", (sid, max_elec_id))
	unused_elecs = []
	for elec_id in unused_elec_id:
		unused_elecs.append(event.Election.load_by_id(elec_id))

	# Step 3: Insert elections where there's time and adjust predicted start times as necessary, if num_elections < 2 then create them where necessary
	i = 1
	running_time = current[sid].start_actual + current[sid].length()
	if len(next[sid]) > 0:
		next[sid][0].start = running_time
	while i < len(next[sid]):
		next_start = next[sid][i].start
		gap = next_start - running_time
		next_elec_i = None
		next_elec_length = playlist.get_average_song_length(sid)
		j = i
		while j < len(next[sid]):
			if next[sid][j].is_election:
				next_elec = j
				next_elec_length = next[sid][j].length()
				break
		if not next_elec_i and len(unused_elecs) > 0:
			next_elec_length = unused_elecs[0].length()

		# TODO: This algorithm DEFINITELY needs code/concept review
		# There are potential holes - it is not as comprehensive a scheduler as the previous
		# Rainwave scheduler, however it is vastly simplified.
		# One drawback is that you cannot schedule elections themselves to run at certain times.

		create_elecs = False
		# If the event we're looking at collides with the previous event, adjust this event to start later
		if gap <= 0:
			next[sid][i].start = running_time
			running_time += next[sid][i].length()
		# If we have no elections current in the next list and there's enough time to fit a song, stuff an election in
		# (this automatically takes into account unused elections, based on next_elec_length definition above)
		elif not next_elec_i and gap <= (next_elec_length * 1.4):
			next_elec = None
			# If we have an existing unused election, we can use that (as next_elec_length is already based on the first unused elec, this can happen)
			if len(unused_elecs) > 0:
				next_elec = unused_elecs.pop(0)
			# If not, create a new election timed to the gap (next_elec_length will be the average song length*1.4, so this will happen frequently)
			else:
				next_elec = _create_election(sid, running_time, gap)
			num_elections += 1
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].insert(i, next_elec)
		# If it's more accurate to squeeze a created election in here than adjust the next event, move the event
		# *OR* the next event is too far out and we have elections in hand
		elif next_elec_i and ((gap <= (next_elec_length / 2)) or (gap > (next_elec_length * 1.5))):
			next_elec = next[sid].pop(next_elec_i)
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].insert(i, next_elec)
		# The next event is better off aligned
		else:
			next[sid][i].start = running_time
			running_time += next[sid][i].length()
		i += 1

	needed_elecs = config.get_station(sid, "num_planned_elections") - num_elections
	log.debug("create_elec", "Before: Needed elecs: %s // Unused elecs: %s // Current num elections: %s // Next size: %s" % (needed_elecs, len(unused_elecs), num_elections, len(next[sid])))
	# Step 5: If we're at less than X elections available, create them (or use unused ones) and append them
	# No timing is required here, since we're simply outright appending to the end
	# (any elections appearing before a scheduled item would be handled by the block above)
	failures = 0
	while needed_elecs > 0 and failures <= 2:
		next_elec = None
		if len(unused_elecs) > 0:
			next_elec = unused_elecs.pop(0)
		else:
			next_elec = _create_election(sid, running_time)
		next_elec_length = next_elec.length()
		if next_elec_length > 0:
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].append(next_elec)
			num_elections += 1
			needed_elecs -= 1
		else:
			log.error("create_elec", "Election ID %s was faulty - zero length.  Deleting.")
			next_elec.delete()
			failures += 1
	if failures >= 2:
		log.error("create_elec", "Total failure when creating elections.")
	log.debug("create_elec", "After: Unused elecs: %s // Current num elections: %s // Next size: %s" % (len(unused_elecs), num_elections, len(next[sid])))
Esempio n. 7
0
def _create_elections(sid):
	# Step, er, 0: Update the request cache first, so elections have the most recent data to work with
	# (the entire requests module depends on its caches)
	request.update_cache(sid)