tmf.ctf: Move each CtfIteratorManager into its own trace object
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ctf.core / src / org / eclipse / tracecompass / tmf / ctf / core / CtfIteratorManager.java
CommitLineData
53b235e1 1/*******************************************************************************
e471302a 2 * Copyright (c) 2014 Ericsson
53b235e1
MK
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
f0414df8 9 * Contributors:
e471302a 10 * Alexandre Montplaisir - Renamed/extracted from CtfTraceManager
53b235e1 11 *******************************************************************************/
e471302a 12
2bdf0193 13package org.eclipse.tracecompass.tmf.ctf.core;
53b235e1
MK
14
15import java.util.ArrayList;
16import java.util.HashMap;
17import java.util.Random;
6a0ec7bc
AM
18import java.util.concurrent.locks.Lock;
19import java.util.concurrent.locks.ReentrantLock;
53b235e1
MK
20
21/**
6a0ec7bc
AM
22 * A CTF trace iterator manager.
23 *
24 * Each instance of {@link CtfTmfTrace} should possess one of these, which will
25 * manage the iterators that are opened to read that trace. This will allow
26 * controlling the number of opened file handles per trace.
53b235e1
MK
27 *
28 * @author Matthew Khouzam
29 */
6a0ec7bc 30public class CtfIteratorManager {
53b235e1
MK
31 /*
32 * Cache size. Under 1023 on linux32 systems. Number of file handles
33 * created.
34 */
35 private final static int MAX_SIZE = 100;
6a0ec7bc
AM
36
37 /** The map of the cache */
81a2d02e 38 private final HashMap<CtfTmfContext, CtfIterator> fMap;
6a0ec7bc
AM
39
40 /** An array pointing to the same cache. this allows fast "random" accesses */
81a2d02e 41 private final ArrayList<CtfTmfContext> fRandomAccess;
6a0ec7bc
AM
42
43 /** Lock for when we access the two previous data structures */
44 private final Lock fAccessLock = new ReentrantLock();
45
46 /** The parent trace */
53b235e1 47 private final CtfTmfTrace fTrace;
6a0ec7bc
AM
48
49 /** Random number generator */
53b235e1
MK
50 private final Random fRnd;
51
6a0ec7bc
AM
52 /**
53 * Constructor
54 *
55 * @param trace
56 * The trace whose iterators this manager will manage
57 */
e471302a 58 public CtfIteratorManager(CtfTmfTrace trace) {
a4524c1b
AM
59 fMap = new HashMap<>();
60 fRandomAccess = new ArrayList<>();
53b235e1
MK
61 fRnd = new Random(System.nanoTime());
62 fTrace = trace;
63 }
64
65 /**
66 * This needs explaining: the iterator table is effectively a cache.
67 * Originally the contexts had a 1 to 1 structure with the file handles of a
68 * trace. This failed since there is a limit to how many file handles we can
69 * have opened simultaneously. Then a round-robin scheme was implemented,
70 * this lead up to a two competing contexts syncing up and using the same
71 * file handler, causing horrible slowdowns. Now a random replacement
72 * algorithm is selected. This is the same as used by arm processors, and it
73 * works quite well when many cores so this looks promising for very
74 * multi-threaded systems.
75 *
76 * @param context
77 * the context to look up
ecb12461 78 * @return the iterator referring to the context
53b235e1 79 */
81a2d02e 80 public CtfIterator getIterator(final CtfTmfContext context) {
53b235e1
MK
81 /*
82 * if the element is in the map, we don't need to do anything else.
83 */
6a0ec7bc
AM
84 CtfIterator iter = fMap.get(context);
85 if (iter == null) {
53b235e1 86
6a0ec7bc
AM
87 fAccessLock.lock();
88 try {
53b235e1 89 /*
6a0ec7bc 90 * Assign an iterator to a context.
53b235e1 91 */
6a0ec7bc
AM
92 if (fRandomAccess.size() < MAX_SIZE) {
93 /*
94 * if we're not full yet, just add an element.
95 */
96 iter = fTrace.createIterator();
97 addElement(context, iter);
98
99 } else {
100 /*
101 * if we're full, randomly replace an element
102 */
103 iter = replaceRandomElement(context);
104 }
105 if (context.getLocation() != null) {
106 final CtfLocationInfo location = (CtfLocationInfo) context.getLocation().getLocationInfo();
107 iter.seek(location);
108 }
109 } finally {
110 fAccessLock.unlock();
575beffc 111 }
53b235e1 112 }
6a0ec7bc 113 return iter;
53b235e1
MK
114 }
115
6a0ec7bc
AM
116 /**
117 * Remove an iterator from this manager
118 *
119 * @param context
120 * The context of the iterator to remove
121 */
f0414df8 122 public void removeIterator(CtfTmfContext context) {
6a0ec7bc
AM
123 fAccessLock.lock();
124 try {
125 /* The try below is only to auto-call CtfIterator.close() */
126 try (CtfIterator removed = fMap.remove(context)) {
127 }
128 fRandomAccess.remove(context);
259c81f0 129
6a0ec7bc
AM
130 } finally {
131 fAccessLock.unlock();
132 }
f0414df8
SD
133 }
134
53b235e1
MK
135 /**
136 * Add a pair of context and element to the hashmap and the arraylist.
137 *
138 * @param context
139 * the context
140 * @param elem
141 * the iterator
142 */
81a2d02e 143 private void addElement(final CtfTmfContext context,
53b235e1 144 final CtfIterator elem) {
6a0ec7bc
AM
145 fAccessLock.lock();
146 try {
147 fMap.put(context, elem);
148 fRandomAccess.add(context);
149
150 } finally {
151 fAccessLock.unlock();
152 }
53b235e1
MK
153 }
154
155 /**
156 * Replace a random element
157 *
158 * @param context
159 * the context to swap in
160 * @return the iterator of the removed elements.
161 */
6a0ec7bc 162 private CtfIterator replaceRandomElement(final CtfTmfContext context) {
53b235e1
MK
163 /*
164 * This needs some explanation too: We need to select a random victim
165 * and remove it. The order of the elements is not important, so instead
166 * of just calling arraylist.remove(element) which has an O(n)
167 * complexity, we pick an random number. The element is swapped out of
168 * the array and removed and replaced in the hashmap.
169 */
6a0ec7bc
AM
170 fAccessLock.lock(); // just in case, should only be called when already locked
171 try {
172 final int size = fRandomAccess.size();
173 final int pos = fRnd.nextInt(size);
174 final CtfTmfContext victim = fRandomAccess.get(pos);
175 fRandomAccess.set(pos, context);
176 final CtfIterator elem = fMap.remove(victim);
177 fMap.put(context, elem);
178 victim.dispose();
179 return elem;
180
181 } finally {
182 fAccessLock.unlock();
183 }
53b235e1
MK
184 }
185
6a0ec7bc
AM
186 /**
187 * Dispose this iterator manager, which will close all the remaining
188 * iterators.
189 */
190 public void dispose() {
191 fAccessLock.lock();
192 try {
193 for (CtfIterator iterator : fMap.values()) {
194 iterator.dispose();
195 }
196 fMap.clear();
197 fRandomAccess.clear();
198
199 } finally {
200 fAccessLock.unlock();
5d1c6919 201 }
5d1c6919 202 }
e471302a 203}
This page took 0.069335 seconds and 5 git commands to generate.