Exemplo n.º 1
0
    def __init__(self,
                 size: int,
                 trained_net: TorchFeedforwardNN,
                 sketches_num: int,
                 sketches_additive_factor: float,
                 sketches_probability: float,
                 time_window: float,
                 update_sample_size: int=5):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param trained_net: Trained neural network.
        :param sketches_num: Number of count-min sketches.
        :param sketches_additive_factor: Additive factor of sketches.
        :param sketches_probability: Probability for sketches.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)
        self.__trained_net = trained_net

        self.__count_min_sketches = []
        self.__additive_factor = sketches_additive_factor
        self.__probability = sketches_probability
        for i in range(sketches_num):
            sketch = CountMinSketch.construct_by_constraints(sketches_additive_factor, sketches_probability)
            self.__count_min_sketches.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size
Exemplo n.º 2
0
    def __init__(self,
                 size: int,
                 counter_num: int,
                 time_window: float,
                 update_sample_size: int = 5):
        """
        Construct a new AveragePredictorCache object.
        :param size: Size of cache.
        :param counter_num: Number of counters.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)

        self.__counters = []
        for i in range(counter_num):
            sketch = FullCounter()
            self.__counters.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size
Exemplo n.º 3
0
 def __init__(self, size):
     """
     Construct a new LRUCache object.
     :param size: Size of cache.
     """
     super().__init__(size)
     self.__access_priority_dict = PriorityDict()
Exemplo n.º 4
0
    def __init__(self,
                 size: int,
                 trained_net: TorchFeedforwardNN,
                 counter_num: int,
                 time_window: float,
                 update_sample_size: int=5,
                 online_learning: bool=False,
                 cf_coef: float=0.5,
                 learning_rate: float=0.001,
                 batch_size: int=1000):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param trained_net: Trained neural network.
        :param counter_num: Number of counters.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        :param online_learning: Use online learning mechanism.
        :param cf_coef: Coefficient to prevent catastrophic forgetting while learning online.
        :param learning_rate: Learning rate for online learning.
        :param batch_size: Batch size used while learning.
        """
        super().__init__(size)
        if trained_net is not None:
            self.__trained_net = trained_net
        else:
            # self.__trained_net = TorchFeedforwardNN([counter_num + 1, 128, 128, 1], "l_relu", "l_relu")
            self.__trained_net = None

        self.__counters = []
        for i in range(counter_num):
            sketch = FullCounter()
            self.__counters.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size

        self.__online = online_learning
        self.__cf_coef = cf_coef
        assert 0.0 < self.__cf_coef < 1.0

        past_df_count = 1
        while self.__cf_coef ** past_df_count > 0.01:
            past_df_count += 1
        self.__past_dfs = [None] * past_df_count
        self.__past_pop = [None] * past_df_count
        self.__learning_rate = learning_rate
        self.__batch_size = batch_size
Exemplo n.º 5
0
    def __init__(self,
                 size: int,
                 path_to_mod_trace: str):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param path_to_mod_trace: Path to modified trace CSV file.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)

        input_df = pd.read_csv(path_to_mod_trace, header=None, names=["from_start", "from_prev", "id", "future_pop"])
        self.__trace_iter = input_df.iterrows()

        self.__priority_dict = PriorityDict()
Exemplo n.º 6
0
 def __init__(self, size):
     """
     Construct a new ARCache object.
     :param size: Size of cache.
     """
     super().__init__(size)
     self.__T1 = PriorityDict()
     self.__T2 = PriorityDict()
     self.__B1 = PriorityDict()
     self.__B2 = PriorityDict()
     self.__p = 0
     self.__c = size
Exemplo n.º 7
0
class FutureInfoCache(AbstractCache):

    # region Private variables

    __counters = None
    __trace_iter = None
    __priority_dict = None
    __update_sample_size = 0

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self,
                 size: int,
                 path_to_mod_trace: str):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param path_to_mod_trace: Path to modified trace CSV file.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)

        input_df = pd.read_csv(path_to_mod_trace, header=None, names=["from_start", "from_prev", "id", "future_pop"])
        self.__trace_iter = input_df.iterrows()

        self.__priority_dict = PriorityDict()

    # endregion

    # region Private methods

    def __predict_pop(self, id_, time: float) -> float:
        """
        Fetch the popularity from the modified trace.
        :param id_: ID of the object.
        :param time: Time of arrival.
        :return: Fetched popularity.
        """
        _, row = next(self.__trace_iter)
        assert int(row.id) == int(id_)
        return row.future_pop

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        if len(self.__priority_dict) < self.__update_sample_size:
            real_update_size = len(self.__priority_dict)
        else:
            real_update_size = self.__update_sample_size

        pred_pop = self.__predict_pop(id_, time)
        self.__priority_dict[id_] = pred_pop

        # sample = random.sample(self.__priority_dict.keys(), real_update_size)
        # for id_ in sample:
        #     pred_pop = self.__predict_pop(id_, time)
        #     self.__priority_dict[id_] = pred_pop

    def _process_cache_miss(self, id_, size, time, metadata):
        pred_pop = self.__predict_pop(id_, time)
        if self._free_cache > 0:
            self._store_object(id_, size)
            self.__priority_dict[id_] = pred_pop

        else:
            candidate = self.__priority_dict.smallest()
            if pred_pop > self.__priority_dict[candidate]:
                self._remove_object(candidate)
                self._store_object(id_, size)
                self.__priority_dict.pop_smallest()
                self.__priority_dict[id_] = pred_pop
Exemplo n.º 8
0
class FeedforwardNNCacheTorch(AbstractCache):

    # region Private variables

    __count_min_sketches = None
    __additive_factor = 0.0
    __probability = 0.0
    __trained_net = None
    __time_window = 0.0
    __processed_windows = 0
    __from_window_start = 0.0
    __priority_dict = None
    __update_sample_size = 0

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self,
                 size: int,
                 trained_net: TorchFeedforwardNN,
                 sketches_num: int,
                 sketches_additive_factor: float,
                 sketches_probability: float,
                 time_window: float,
                 update_sample_size: int=5):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param trained_net: Trained neural network.
        :param sketches_num: Number of count-min sketches.
        :param sketches_additive_factor: Additive factor of sketches.
        :param sketches_probability: Probability for sketches.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)
        self.__trained_net = trained_net

        self.__count_min_sketches = []
        self.__additive_factor = sketches_additive_factor
        self.__probability = sketches_probability
        for i in range(sketches_num):
            sketch = CountMinSketch.construct_by_constraints(sketches_additive_factor, sketches_probability)
            self.__count_min_sketches.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size

    # endregion

    # region Private methods

    def __predict_pop(self, id_, time: float) -> float:
        """
        Predict popularity of object using NN and sketches.
        :param id_: ID of the object.
        :param time: Time of arrival.
        :return: Predicted popularity.
        """
        prediction_row = []
        for sketch in self.__count_min_sketches:
            frac = sketch.get_request_fraction(id_)
            frac = -np.log(frac + 10**-15)
            prediction_row.append(frac)

        window_time = (time - self.__time_window * self.__processed_windows) / self.__time_window
        prediction_row.append(window_time)

        matr = torch.from_numpy(np.matrix([prediction_row]))
        pop_log = float(self.__trained_net(matr))
        pop = np.exp(-pop_log) - 10**-15
        return pop

    def __update_time(self, time: float):
        """
        Updates time related activity - active sketches, time from window start, etc.
        :param time: Time of object arrival.
        """
        added_time = time - self.__time_window * self.__processed_windows
        self.__from_window_start += added_time

        while self.__from_window_start > self.__time_window:
            self.__processed_windows += 1
            self.__from_window_start -= self.__time_window
            del self.__count_min_sketches[0]
            sketch = CountMinSketch.construct_by_constraints(self.__additive_factor, self.__probability)
            self.__count_min_sketches.append(sketch)

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__count_min_sketches[-1].update_counters(id_)
        if len(self.__priority_dict) < self.__update_sample_size:
            real_update_size = len(self.__priority_dict)
        else:
            real_update_size = self.__update_sample_size

        pred_pop = self.__predict_pop(id_, time)
        self.__priority_dict[id_] = pred_pop

        sample = random.sample(self.__priority_dict.keys(), real_update_size)
        for i in sample:
            pred_pop = self.__predict_pop(i, time)
            self.__priority_dict[i] = pred_pop

    def _process_cache_miss(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__count_min_sketches[-1].update_counters(id_)
        pred_pop = self.__predict_pop(id_, time)
        if self._free_cache > 0:
            self._store_object(id_, size)
            self.__priority_dict[id_] = pred_pop

        else:
            candidate = self.__priority_dict.smallest()
            if pred_pop > self.__priority_dict[candidate]:
                self._remove_object(candidate)
                self._store_object(id_, size)
                self.__priority_dict.pop_smallest()
                self.__priority_dict[id_] = pred_pop
Exemplo n.º 9
0
class ARCache(AbstractCache):
    """
    ARCache implements cache with Adaptive Replacement policy.
    Inherits AbstractCache.
    """
    # region Private variables

    __T1 = None
    __T2 = None
    __B1 = None
    __B2 = None
    __p = 0
    __c = 0

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self, size):
        """
        Construct a new ARCache object.
        :param size: Size of cache.
        """
        super().__init__(size)
        self.__T1 = PriorityDict()
        self.__T2 = PriorityDict()
        self.__B1 = PriorityDict()
        self.__B2 = PriorityDict()
        self.__p = 0
        self.__c = size

    # endregion

    # region Private methods

    # REPLACE procedure from ARC paper
    def __replace(self, id_, time):
        if (not self.__T1.empty()) and (
            (len(self.__T1) > self.__p) or
            (id_ in self.__B2 and len(self.__T1) == self.__p)):
            rem = self.__T1.pop_smallest()
            self._remove_object(rem)
            self.__B1[rem] = time
        else:
            rem = self.__T2.pop_smallest()
            self._remove_object(rem)
            self.__B2[rem] = time

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        """
        Move object to MRU in T2. Case I in ARC paper.
        :param id_: ID of the object.
        :param size: Size of the object.
        :param time: Time of the request.
        """
        if size != 1:
            raise CachingObjectError(
                "Objects of size 1 only supported in ARC.")

        # ARC Case I
        if id_ in self.__T1:
            self.__T1[id_] = -1.0
            p = self.__T1.pop_smallest()
            assert p == id_
        self.__T2[id_] = time

    def _process_cache_miss(self, id_, size, time, metadata):
        """
        Implementing cases II-IV in ARC paper.
        :param id_: ID of the object
        :param size: Size of the object
        :param time: Time of the request
        """
        if size != 1:
            raise CachingObjectError(
                "Objects of size 1 only supported in ARC.")

        # ARC Case II
        if id_ in self.__B1:
            if len(self.__B1) >= len(self.__B2):
                delta1 = 1
            else:
                delta1 = len(self.__B2) / len(self.__B1)
            self.__p = min(self.__p + delta1, self.__c)

            self.__replace(id_, time)

            self.__B1[id_] = -1.0
            p = self.__B1.pop_smallest()
            assert p == id_

            self.__T2[id_] = time
            self._store_object(id_, size)

        # ARC Case III
        elif id_ in self.__B2:
            if len(self.__B2) >= len(self.__B1):
                delta2 = 1
            else:
                delta2 = len(self.__B1) / len(self.__B2)
            self.__p = max(self.__p - delta2, 0)

            self.__replace(id_, time)

            self.__B2[id_] = -1.0
            p = self.__B2.pop_smallest()
            assert p == id_

            self.__T2[id_] = time
            self._store_object(id_, size)

        # ARC Case IV
        else:
            # Case A
            if len(self.__T1) + len(self.__B1) == self.__c:
                if len(self.__T1) < self.__c:
                    self.__B1.pop_smallest()
                    self.__replace(id_, time)
                else:
                    rem = self.__T1.pop_smallest()
                    self._remove_object(rem)

            # Case B
            elif len(self.__T1) + len(self.__B1) < self.__c:
                if len(self.__T1) + len(self.__B1) + len(self.__T2) + len(
                        self.__B2) >= self.__c:
                    if len(self.__T1) + len(self.__B1) + len(self.__T2) + len(
                            self.__B2) == 2 * self.__c:
                        self.__B2.pop_smallest()
                    self.__replace(id_, time)
            else:
                raise AlgorithmError(
                    "Should not happen according to ARC algorithm.")

            self._store_object(id_, size)
            self.__T1[id_] = time
Exemplo n.º 10
0
class FeedforwardNNCacheFullTorch(AbstractCache):

    # region Private variables

    __counters = None
    __trained_net = None
    __time_window = 0.0
    __processed_windows = 0
    __from_window_start = 0.0
    __priority_dict = None
    __update_sample_size = 0
    __prev_time = None

    __online = False
    __cf_coef = 0.0
    __past_dfs = []
    __past_pop = []
    __learning_rate = 0.0
    __batch_size = 0

    __metadata_cache = {}

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self,
                 size: int,
                 trained_net: TorchFeedforwardNN,
                 counter_num: int,
                 time_window: float,
                 update_sample_size: int=5,
                 online_learning: bool=False,
                 cf_coef: float=0.5,
                 learning_rate: float=0.001,
                 batch_size: int=1000):
        """
        Construct a new FeedforwardNNCache object.
        :param size: Size of cache.
        :param trained_net: Trained neural network.
        :param counter_num: Number of counters.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        :param online_learning: Use online learning mechanism.
        :param cf_coef: Coefficient to prevent catastrophic forgetting while learning online.
        :param learning_rate: Learning rate for online learning.
        :param batch_size: Batch size used while learning.
        """
        super().__init__(size)
        if trained_net is not None:
            self.__trained_net = trained_net
        else:
            # self.__trained_net = TorchFeedforwardNN([counter_num + 1, 128, 128, 1], "l_relu", "l_relu")
            self.__trained_net = None

        self.__counters = []
        for i in range(counter_num):
            sketch = FullCounter()
            self.__counters.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size

        self.__online = online_learning
        self.__cf_coef = cf_coef
        assert 0.0 < self.__cf_coef < 1.0

        past_df_count = 1
        while self.__cf_coef ** past_df_count > 0.01:
            past_df_count += 1
        self.__past_dfs = [None] * past_df_count
        self.__past_pop = [None] * past_df_count
        self.__learning_rate = learning_rate
        self.__batch_size = batch_size

    # endregion

    # region Private methods

    def __predict_pop(self, id_, time: float, new_entry: bool, metadata: dict) -> float:
        """
        Predict popularity of object using NN and sketches.
        :param id_: ID of the object.
        :param time: Time of arrival.
        :param new_entry: Prediction is for newly arrived object.
        :param metadata: Some additional metadata.
        :return: Predicted popularity.
        """
        prediction_row = []
        for sketch in self.__counters:
            frac = sketch.get_request_fraction(id_)
            frac = -np.log(frac + 10**-15)
            prediction_row.append(frac)

        window_time = self.__from_window_start / self.__time_window
        prediction_row.append(window_time)

        if metadata is not None and len(metadata) > 0:
            if "size" in metadata:
                prediction_row.append(np.log(metadata["size"] + 10**-15))

            if "daytime" in metadata:
                prediction_row.append(metadata["daytime"])

        if self.__trained_net is None:
            # self.__trained_net = TorchFeedforwardNN([len(prediction_row), 128, 128, 1], "l_relu", "l_relu")
            self.__trained_net = TorchFeedforwardNN([len(prediction_row), 128, 128, 1], None, None) # adding linear predictor test

        # np_matr = np.matrix([prediction_row])
        matr = torch.tensor([prediction_row])
        pop_log = float(self.__trained_net(matr))
        pop = np.exp(-pop_log) - 10**-15

        if self.__online and new_entry:
            if self.__past_dfs[0] is None:
                self.__past_dfs[0] = []
                self.__past_pop[0] = []

            self.__past_dfs[0].append(prediction_row)
            self.__past_pop[0].append(id_)

        return pop

    def __learn_online(self):
        """
        Start online learning.
        """
        # self.__past_dfs[0] = np.matrix(self.__past_dfs[0])
        self.__past_dfs[0] = torch.tensor(self.__past_dfs[0])

        self.__past_pop[0] = [self.__counters[-1].get_request_fraction(x) + 10**-15 for x in self.__past_pop[0]]
        self.__past_pop[0] = [[-np.log(x)] for x in self.__past_pop[0]]
        self.__past_pop[0] = torch.tensor(self.__past_pop[0])

        for i, inp_all in enumerate(self.__past_dfs):
            if inp_all is None:
                continue

            target_all = self.__past_pop[i]

            weight = self.__cf_coef**i

            train_loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(inp_all, target_all),
                                                       batch_size=self.__batch_size)

            for inp, target in train_loader:
                self.__trained_net.backpropagation_learn(inp, target, self.__learning_rate, False, False, weight)

        for i in reversed(range(len(self.__past_dfs) - 1)):
            self.__past_pop[i + 1] = self.__past_pop[i]
            self.__past_dfs[i + 1] = self.__past_dfs[i]

        self.__past_dfs[0] = []
        self.__past_pop[0] = []

    def __update_time(self, time: float):
        """
        Updates time related activity - active sketches, time from window start, etc.
        :param time: Time of object arrival.
        """
        if self.__prev_time is None:
            self.__prev_time = time

        added_time = time - self.__prev_time
        assert added_time >= 0.0
        self.__prev_time = time

        self.__from_window_start += added_time

        while self.__from_window_start > self.__time_window:
            if self.__online:
                self.__learn_online()

            self.__processed_windows += 1
            self.__from_window_start -= self.__time_window
            del self.__counters[0]
            sketch = FullCounter()
            self.__counters.append(sketch)

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__counters[-1].update_counters(id_)
        self.__metadata_cache[id_] = metadata

        if len(self.__priority_dict) < self.__update_sample_size:
            real_update_size = len(self.__priority_dict)
        else:
            real_update_size = self.__update_sample_size

        pred_pop = self.__predict_pop(id_, time, True, metadata)
        self.__priority_dict[id_] = pred_pop

        sample = random.sample(self.__priority_dict.keys(), real_update_size)
        for i in sample:
            pred_pop = self.__predict_pop(i, time, False, self.__metadata_cache[i])
            self.__priority_dict[i] = pred_pop

    def _process_cache_miss(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__counters[-1].update_counters(id_)
        self.__metadata_cache[id_] = metadata

        pred_pop = self.__predict_pop(id_, time, True, metadata)
        assert not math.isnan(pred_pop)

        if self._free_cache > 0:
            self._store_object(id_, size)
            self.__priority_dict[id_] = pred_pop

        else:
            candidate = self.__priority_dict.smallest()
            if pred_pop > self.__priority_dict[candidate]:
                del self.__metadata_cache[candidate]
                self._remove_object(candidate)
                self._store_object(id_, size)
                self.__priority_dict.pop_smallest()
                self.__priority_dict[id_] = pred_pop
            else:
                del self.__metadata_cache[id_]
Exemplo n.º 11
0
class AveragePredictorCache(AbstractCache):

    # region Private variables

    __counters = None
    __trained_net = None
    __time_window = 0.0
    __processed_windows = 0
    __from_window_start = 0.0
    __priority_dict = None
    __update_sample_size = 0
    __prev_time = None

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self,
                 size: int,
                 counter_num: int,
                 time_window: float,
                 update_sample_size: int = 5):
        """
        Construct a new AveragePredictorCache object.
        :param size: Size of cache.
        :param counter_num: Number of counters.
        :param time_window: Time window of one sketch activity.
        :param update_sample_size: How many items popularity to update when processing cache hit.
        """
        super().__init__(size)

        self.__counters = []
        for i in range(counter_num):
            sketch = FullCounter()
            self.__counters.append(sketch)

        self.__time_window = time_window
        self.__processed_windows = 0
        self.__from_window_start = 0.0

        self.__priority_dict = PriorityDict()

        self.__update_sample_size = update_sample_size

    # endregion

    # region Private methods

    def __predict_pop(self, id_, time: float) -> float:
        """
        Predict popularity of object using NN and sketches.
        :param id_: ID of the object.
        :param time: Time of arrival.
        :return: Predicted popularity.
        """
        n = len(self.__counters)
        window_time = (time - self.__time_window *
                       self.__processed_windows) / self.__time_window

        w = 1.0 / (n - 1 + window_time**2)
        w_0 = window_time**2 / (n - 1 + window_time**2)

        prediction_row = []
        for sketch in self.__counters[:-1]:
            frac = sketch.get_request_fraction(id_)
            prediction_row.append(frac * w)

        frac = self.__counters[-1].get_request_fraction(id_)
        prediction_row.append(frac * w_0)

        pop = float(np.sum(prediction_row))
        return pop

    def __update_time(self, time: float):
        """
        Updates time related activity - active sketches, time from window start, etc.
        :param time: Time of object arrival.
        """
        if self.__prev_time is None:
            self.__prev_time = time

        added_time = time - self.__prev_time
        assert added_time >= 0.0
        self.__prev_time = time

        self.__from_window_start += added_time

        while self.__from_window_start > self.__time_window:
            self.__processed_windows += 1
            self.__from_window_start -= self.__time_window
            del self.__counters[0]
            sketch = FullCounter()
            self.__counters.append(sketch)

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__counters[-1].update_counters(id_)
        if len(self.__priority_dict) < self.__update_sample_size:
            real_update_size = len(self.__priority_dict)
        else:
            real_update_size = self.__update_sample_size

        pred_pop = self.__predict_pop(id_, time)
        self.__priority_dict[id_] = pred_pop

        sample = random.sample(self.__priority_dict.keys(), real_update_size)
        for i in sample:
            pred_pop = self.__predict_pop(i, time)
            self.__priority_dict[i] = pred_pop

    def _process_cache_miss(self, id_, size, time, metadata):
        self.__update_time(time)
        self.__counters[-1].update_counters(id_)
        pred_pop = self.__predict_pop(id_, time)
        if self._free_cache > 0:
            self._store_object(id_, size)
            self.__priority_dict[id_] = pred_pop

        else:
            candidate = self.__priority_dict.smallest()
            if pred_pop > self.__priority_dict[candidate]:
                self._remove_object(candidate)
                self._store_object(id_, size)
                self.__priority_dict.pop_smallest()
                self.__priority_dict[id_] = pred_pop
Exemplo n.º 12
0
class LRUCache(AbstractCache):
    """
    LRUCache implements cache with Least Recently Used policy.
    Inherits AbstractCache.
    """

    # region Private variables

    __access_priority_dict = None

    # endregion

    # region Protected variables

    # endregion

    # region Public variables, properties

    # endregion

    # region Constructors

    def __init__(self, size):
        """
        Construct a new LRUCache object.
        :param size: Size of cache.
        """
        super().__init__(size)
        self.__access_priority_dict = PriorityDict()

    # endregion

    # region Private methods

    # endregion

    # region Protected methods

    def _process_cache_hit(self, id_, size, time, metadata):
        """
        Only update last access time for cached objects.
        :param id_: ID of the object.
        :param size: Size of the object.
        :param time: Time of the request.
        """
        self.__access_priority_dict[id_] = time

    def _process_cache_miss(self, id_, size, time, metadata):
        """
        Remove oldest accessed object (LRU policy). Store requested object.
        :param id_: ID of the object.
        :param size: Size of the object.
        :param time: Time of the request.
        :raises ObjectTooLargeError: If the object is too large to be stored in the cache.
        """
        free = self._free_cache

        while free < size:
            if len(self.__access_priority_dict) == 0:
                raise NotEnoughStorage(
                    f'Cache cannot hold object of size {size}')

            i = self.__access_priority_dict.pop_smallest()
            self._remove_object(i)
            free = self._free_cache

        self.__access_priority_dict[id_] = time
        self._store_object(id_, size)