package com.linkedin.databus.core.util; /* * * Copyright 2013 LinkedIn Corp. 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. * */ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Set; /** * A collection that keeps track of object generations (age). Each object is associated with an * integer age. Objects' age increases with each use and they get removed once they reach a max age. * * One use for this is to keep track of retries. * * @author cbotev * * @param <T> the type of objects to track */ public class ObjectGenerationTracker<T> { private static final int DEFAULT_SIZE = 16; private static class AgedObject<U> { private final U _object; private int _age; public AgedObject(U o) { _age = 0; _object = o; } public int getAge() { return _age; } public int age(int delta) { _age += delta; return _age; } @Override public boolean equals(Object o) { if (null == o || !(o instanceof AgedObject<?>)) return false; return _object == ((AgedObject<?>)o)._object; } @Override public int hashCode() { return _object.hashCode(); } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append("{\"age\":"); result.append(_age); result.append(", \"object\":"); result.append(_object.toString()); result.append('}'); return result.toString(); } } private final IdentityHashMap<T, AgedObject<T>> _objects; private final List<Set<AgedObject<T>>> _generations; private final int _maxAge; public ObjectGenerationTracker(int maxAge) { assert maxAge >= 0 : "negative max age"; _maxAge = maxAge; _objects = new IdentityHashMap<T, AgedObject<T>>(DEFAULT_SIZE); _generations = new ArrayList<Set<AgedObject<T>>>(_maxAge + 1); for (int i = 0; i <= _maxAge; ++i) { _generations.add(new HashSet<AgedObject<T>>(DEFAULT_SIZE)); } } /** * Adds a new object with age 0. If the object exists, nothing happens. * @param o the object to add */ public void add(T o) { AgedObject<T> agedObj = _objects.get(o); if (null == agedObj) { agedObj = new AgedObject<T>(o); _objects.put(o, agedObj); _generations.get(0).add(agedObj); } } /** * Adds all objects to the collection. * * @see #add(Object) */ public void addAll(T... objs) { for (T o: objs) add(o); } /** * Adds all objects to the collection. * * @see #add(Object) */ public void addAll(Collection<T> objs) { for (T o: objs) add(o); } /** * Ages the object in the collection with 1. * @param o the object to age * @return the new age of the object; if that age is greater than the max age, the object has been * removed from the collection; -1 if the object was not in the collection */ public int age(T o) { return age(o, 1); } /** * Ages the object in the collection with the specified delta. * @param o the object to age * @param delta the increment in age * @return the new age of the object; if that age is greater than the max age, the object has been * removed from the collection; -1 if the object was not in the collection */ public int age(T o, int delta) { assert delta > 0 : "non-positive delta"; AgedObject<T> agedObj = _objects.get(o); if (null == agedObj) return -1; _generations.get(agedObj.getAge()).remove(agedObj); int newAge = agedObj.age(delta); if (newAge <= _maxAge) _generations.get(newAge).add(agedObj); return newAge; } /** Returns the maximum allowed age*/ public int getMaxAge() { return _maxAge; } /** Returns the number of objects in the collection */ public int size() { return _objects.size(); } }