| /******************************************************************************* |
| * Copyright (c) 2016 École Polytechnique de Montréal |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.core.statesystem; |
| |
| import java.util.ArrayDeque; |
| import java.util.PriorityQueue; |
| import java.util.Queue; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; |
| |
| /** |
| * This class allows to recycle state system attributes. Instead of creating a |
| * lot of short-lived attributes, it is sometimes useful to re-use an attribute |
| * (and its whole sub-tree) that was previously used and is no longer required. |
| * This class keeps a list of children attributes of a base quark and grows that |
| * list as needed. |
| * |
| * @author Geneviève Bastien |
| * @since 2.0 |
| */ |
| public class TmfAttributePool { |
| |
| private final ITmfStateSystemBuilder fSs; |
| private final Integer fBaseQuark; |
| private final Queue<@Nullable Integer> fAvailableQuarks; |
| private final Set<Integer> fQuarksInUse = new TreeSet<>(); |
| private int fCount = 0; |
| |
| /** |
| * The type of queue |
| */ |
| public enum QueueType { |
| /** |
| * First In First Out, available attributes are stored and returned in |
| * the order in which they are recycled |
| */ |
| FIFO, |
| /** |
| * Available attributes are returned by their number, so attributes with |
| * lower numbers will be used more often |
| */ |
| PRIORITY |
| } |
| |
| /** |
| * Constructor |
| * |
| * @param ss |
| * The state system |
| * @param baseQuark |
| * The base quark under which to add the recyclable attributes |
| */ |
| public TmfAttributePool(ITmfStateSystemBuilder ss, Integer baseQuark) { |
| this(ss, baseQuark, QueueType.FIFO); |
| } |
| |
| /** |
| * Constructor |
| * |
| * @param ss |
| * The state system |
| * @param baseQuark |
| * The base quark under which to add the recyclable attributes |
| * @param type |
| * The type of queue to use for the attribute pool |
| */ |
| public TmfAttributePool(ITmfStateSystemBuilder ss, Integer baseQuark, QueueType type) { |
| fSs = ss; |
| try { |
| /* Make sure the base quark is in range */ |
| ss.getParentAttributeQuark(baseQuark); |
| fBaseQuark = baseQuark; |
| } catch (IndexOutOfBoundsException e) { |
| throw new IllegalArgumentException("The quark used as base for the attribute pool does not exist"); //$NON-NLS-1$ |
| } |
| switch (type) { |
| case FIFO: |
| fAvailableQuarks = new ArrayDeque<>(); |
| break; |
| case PRIORITY: |
| fAvailableQuarks = new PriorityQueue<>(); |
| break; |
| default: |
| throw new IllegalArgumentException("Wrong queue type"); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Get an available attribute quark. If there is one available, it will be |
| * reused, otherwise a new quark will be created under the base quark. The |
| * name of the attributes is a sequential integer. So the first quark to be |
| * added will be named '0', the next one '1', etc. |
| * |
| * @return An available quark |
| */ |
| public synchronized int getAvailable() { |
| Integer quark = fAvailableQuarks.poll(); |
| if (quark == null) { |
| quark = fSs.getQuarkRelativeAndAdd(fBaseQuark, String.valueOf(fCount)); |
| fCount++; |
| } |
| fQuarksInUse.add(quark); |
| return quark; |
| } |
| |
| /** |
| * Recycle a quark so that it can be reused by calling the |
| * {@link #getAvailable()} method. The quark has to have been obtained from |
| * a previous call to {@link #getAvailable()}. It will set the quark's value |
| * in the state system to a null value. |
| * |
| * It is assumed that it will be reused in the same context each time, so |
| * all children are kept and set to null in this method. The quarks are |
| * still available for the caller, nothing prevents from re-using them |
| * without referring to this class. That means if any attribute's value need |
| * to be non-null after recycling the quark, the caller can do it after |
| * calling this method. |
| * |
| * @param quark |
| * The quark to recycle. |
| * @param ts |
| * The timestamp at which to close this attribute. |
| */ |
| public synchronized void recycle(int quark, long ts) { |
| if (!fQuarksInUse.remove(quark)) { |
| throw new IllegalArgumentException("Quark " + quark + " is not in use at time " + ts); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| fSs.removeAttribute(ts, quark); |
| fAvailableQuarks.add(quark); |
| } |
| |
| } |