def __init__(self, _time, milliseconds, bucket_numbers,
              bucket_data_length, enabled):
     self.time = _time
     self.milliseconds = milliseconds
     self.buckets = BucketCircular(bucket_numbers)
     self.bucket_numbers = bucket_numbers
     self.bucket_data_length = bucket_data_length
     self.enabled = enabled
     self.snapshot = PercentileSnapshot(0)
     self._new_bucket_lock = RLock()
class RollingPercentile(object):

    def __init__(self, _time, milliseconds, bucket_numbers,
                 bucket_data_length, enabled):
        self.time = _time
        self.milliseconds = milliseconds
        self.buckets = BucketCircular(bucket_numbers)
        self.bucket_numbers = bucket_numbers
        self.bucket_data_length = bucket_data_length
        self.enabled = enabled
        self.snapshot = PercentileSnapshot(0)
        self._new_bucket_lock = RLock()

    def buckets_size_in_milliseconds(self):
        return self.milliseconds / self.bucket_numbers

    def current_bucket(self):
        current_time = self.time.current_time_in_millis()
        current_bucket = self.buckets.peek_last()

        if current_bucket is not None and current_time < (current_bucket.window_start + self.buckets_size_in_milliseconds()):
            return current_bucket

        with self._new_bucket_lock:
            # If we didn't find the current bucket above, then we have to
            # create one.
            if self.buckets.peek_last() is None:
                new_bucket = Bucket(current_time, self.bucket_data_length)
                self.buckets.add_last(new_bucket)
                return new_bucket
            else:
                for i in range(self.bucket_numbers):
                    last_bucket = self.buckets.peek_last()
                    if current_time < (last_bucket.window_start + self.buckets_size_in_milliseconds()):
                        return last_bucket
                    elif current_time - (last_bucket.window_start + self.buckets_size_in_milliseconds()) > self.milliseconds:
                        self.reset()
                        return self.current_bucket()
                    else:
                        all_buckets = [b for b in self.buckets]
                        self.buckets.add_last(Bucket(last_bucket.window_start + self.buckets_size_in_milliseconds(), self.bucket_data_length))
                        self.snapshot = PercentileSnapshot(*all_buckets)

                return self.buckets.peek_last()

        # we didn't get the lock so just return the latest bucket while
        # another thread creates the next one
        current_bucket = self.buckets.peek_last()
        if current_bucket is not None:
            return current_bucket
        else:
            # The rare scenario where multiple threads raced to create the
            # very first bucket wait slightly and then use recursion while
            # the other thread finishes creating a bucket
            time.sleep(5)
            self.current_bucket()

    def add_value(self, *values):
        ''' Add value (or values) to current bucket.
        '''

        if not self.enabled:
            return

        for value in values:
            self.current_bucket().data.add_value(value)

    def percentile(self, percentile):
        if not self.enabled:
            return -1

        # Force logic to move buckets forward in case other requests aren't
        # making it happen
        self.current_bucket()

        # Fetch the current snapshot
        return self.current_percentile_snapshot().percentile(percentile)

    def current_percentile_snapshot(self):
        return self.snapshot

    def mean(self):
        if not self.enabled:
            return -1

        # Force logic to move buckets forward in case other requests aren't
        # making it happen
        self.current_bucket()

        # Fetch the current snapshot
        return self.current_percentile_snapshot().mean()