// Copyright 2016 Twitter. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.twitter.heron.simulator.utils; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; /** * Rotating Map maintains a list of unordered maps. * Every time a rotate is called, it drops the * last map and instantiates a new map at the head * of the list. The create operation adds elements * to the front map of the list. The anchor and remove * operation do their operations starting from the * front of the list to the back. */ public class RotatingMap { private final LinkedList<Map<Long, Long>> buckets = new LinkedList<>(); // Creates a rotating map with nBuckets maps public RotatingMap(int nBuckets) { for (int i = 0; i < nBuckets; i++) { Map<Long, Long> head = new HashMap<>(); buckets.addLast(head); } } // Deletes the last map on the list and // instantiates a new map at the front of the list public void rotate() { Map<Long, Long> m = buckets.removeLast(); buckets.addFirst(new HashMap<Long, Long>()); } // Adds an item to the map at the front of the list public void create(long key, long value) { buckets.getFirst().put(key, value); } // Starting from the front of the list, // it checks if the key already exists and if so // xors another entry to that. Returns true if the // xor turns zero. False otherwise public boolean anchor(long key, long value) { for (Map<Long, Long> m : buckets) { if (m.containsKey(key)) { long currentValue = m.get(key); long newValue = currentValue ^ value; m.put(key, newValue); return newValue == 0; } } return false; } // Starting from the front of the list, checks // if the key was present in the map and if so // removes it. Returns true if the key was removed // from some map. False otherwise. public boolean remove(long key) { for (Map<Long, Long> m : buckets) { if (m.remove(key) != null) { return true; } } return false; } }