def _sanity_check_time(self, start_time, end_time): assert isinstance(start_time, datetime) assert isinstance(end_time, datetime) assert start_time < end_time # TODO(marcua): turn these into a value error if (((datetime_to_epoch_time(start_time) % self._bucket_width) != 0) or ((datetime_to_epoch_time(end_time) % self._bucket_width) != 0)): raise ValueError('start_time and end_time must be on bucket_width ' 'boundaries')
def _get_timeframe_bounds(self, timeframe, bucket_width): """ Get a `bucket_width` aligned `start_time` and `end_time` from a `timeframe` dict """ if bucket_width: bucket_width_seconds = bucket_width bucket_width = epoch_time_to_kronos_time(bucket_width) # TODO(derek): Potential optimization by setting the end_time equal to the # untrusted_time if end_time > untrusted_time and the results are not being # output to the user (only for caching) if timeframe['mode'] == 'recent': # Set end_time equal to now and align to bucket width end_time = datetime_to_kronos_time(datetime.datetime.now()) original_end_time = end_time duration = get_seconds(timeframe['value'], timeframe['scale']) duration = epoch_time_to_kronos_time(duration) start_time = original_end_time - duration if bucket_width: # Align values to the bucket width # TODO(derek): Warn the user that the timeframe has been altered to fit # the bucket width if (end_time % bucket_width) != 0: end_time += bucket_width - (end_time % bucket_width) if (start_time % bucket_width) != 0: start_time -= (start_time % bucket_width) start = kronos_time_to_datetime(start_time) end = kronos_time_to_datetime(end_time) elif timeframe['mode'] == 'range': end = datetime.datetime.strptime(timeframe['to'], DT_FORMAT) end_seconds = datetime_to_epoch_time(end) start = datetime.datetime.strptime(timeframe['from'], DT_FORMAT) start_seconds = datetime_to_epoch_time(start) if bucket_width: # Align values to the bucket width # TODO(derek): Warn the user that the timeframe has been altered to fit # the bucket width start_bump = start_seconds % bucket_width_seconds start -= datetime.timedelta(seconds=start_bump) if (end_seconds % bucket_width_seconds) != 0: end_bump = bucket_width_seconds - (end_seconds % bucket_width_seconds) end += datetime.timedelta(seconds=end_bump) else: raise ValueError("Timeframe mode must be 'recent' or 'range'") return start, end
def _compute_buckets(self, start_time, end_time, compute_missing=True, cache=False, untrusted_time=None, force_recompute=False): self._sanity_check_time(start_time, end_time) # Generate a list of all cached buckets we need to see data for. required_buckets = xrange(int(datetime_to_epoch_time(start_time)), int(datetime_to_epoch_time(end_time)), self._bucket_width) # Get any cached results, grouped by bucket. if force_recompute is True: cached_bucket_iterator = iter([]) else: cached_bucket_iterator = iter(self._cached_results(start_time, end_time)) # Use either the cached results or compute any uncached buckets. # Cache previously uncached results if they are guaranteed to have # happened before the untrusted time. current_cached_bucket = None for required_bucket in required_buckets: if current_cached_bucket is None: try: current_cached_bucket = cached_bucket_iterator.next() except StopIteration: pass emit_events = None if (current_cached_bucket is not None) and ( current_cached_bucket[0] == required_bucket): emit_events = current_cached_bucket[1] current_cached_bucket = None else: if compute_missing is True: # We don't have cached events, so compute the query. emit_events = self._compute_bucket(required_bucket, untrusted_time, cache=cache) else: emit_events = [] for event in emit_events: yield event self._client.flush()