26
26
import org .exist .xmldb .XmldbURI ;
27
27
28
28
import javax .annotation .Nullable ;
29
+ import java .lang .ref .WeakReference ;
29
30
import java .util .ArrayDeque ;
31
+ import java .util .Collections ;
30
32
import java .util .Deque ;
31
33
import java .util .Iterator ;
34
+ import java .util .Map ;
32
35
import java .util .Objects ;
33
- import java .util .concurrent .ConcurrentHashMap ;
34
- import java .util .concurrent .ConcurrentMap ;
36
+ import java .util .WeakHashMap ;
35
37
import java .util .function .BiConsumer ;
36
38
import java .util .function .Consumer ;
37
39
42
44
* @author <a href="mailto:[email protected] ">Adam Retter</a>
43
45
*/
44
46
public class TriggerStatePerThread {
45
-
46
- private static final ConcurrentMap <Txn , Deque <TriggerState >> TRIGGER_STATES = new ConcurrentHashMap <>();
47
+ private static final Map <Thread , TriggerStates > TRIGGER_STATES = Collections .synchronizedMap (new WeakHashMap <>());
47
48
48
49
public static void setAndTest (final Txn txn , final Trigger trigger , final TriggerPhase triggerPhase , final TriggerEvent triggerEvent , final XmldbURI src , final @ Nullable XmldbURI dst ) throws CyclicTriggerException {
49
- final Deque < TriggerState > states = getStates (txn );
50
+ final TriggerStates states = getStates (txn );
50
51
51
52
if (states .isEmpty ()) {
52
53
if (triggerPhase != TriggerPhase .BEFORE ) {
@@ -123,7 +124,7 @@ public static void clearIfFinished(final Txn txn, final TriggerPhase phase) {
123
124
if (phase == TriggerPhase .AFTER ) {
124
125
125
126
int depth = 0 ;
126
- final Deque < TriggerState > states = getStates (txn );
127
+ final TriggerStates states = getStates (txn );
127
128
for (final Iterator <TriggerState > it = states .descendingIterator (); it .hasNext (); ) {
128
129
final TriggerState state = it .next ();
129
130
switch (state .triggerPhase ) {
@@ -144,25 +145,37 @@ public static void clearIfFinished(final Txn txn, final TriggerPhase phase) {
144
145
}
145
146
}
146
147
148
+ public static int keys () {
149
+ return TRIGGER_STATES .size ();
150
+ }
151
+
152
+ public static void clearAll () {
153
+ TRIGGER_STATES .clear ();
154
+ }
155
+
147
156
public static void clear (final Txn txn ) {
148
- TRIGGER_STATES .remove (txn );
157
+ TRIGGER_STATES .remove (Thread . currentThread () );
149
158
}
150
159
151
160
public static boolean isEmpty (final Txn txn ) {
152
161
return getStates (txn ).isEmpty ();
153
162
}
154
163
155
- public static void forEach (BiConsumer <Txn , Deque <TriggerState >> action ) {
164
+ public static void dumpTriggerStates () {
165
+ TRIGGER_STATES .forEach ((k , s ) -> System .err .format ("key: %s, size: %s" , k , s .size ()).println ());
166
+ }
167
+
168
+ public static void forEach (BiConsumer <Thread , TriggerStates > action ) {
156
169
TRIGGER_STATES .forEach (action );
157
170
}
158
171
159
- private static Deque < TriggerState > getStates (final Txn txn ) {
160
- return TRIGGER_STATES .computeIfAbsent (txn , TriggerStatePerThread :: initStates );
172
+ private static TriggerStates getStates (final Txn txn ) {
173
+ return TRIGGER_STATES .computeIfAbsent (Thread . currentThread (), key -> new TriggerStates () );
161
174
}
162
175
163
- private static Deque < TriggerState > initStates (final Txn txn ) {
176
+ private static TriggerStates initStates (final Txn txn ) {
164
177
txn .registerListener (new TransactionCleanUp (txn , TriggerStatePerThread ::clear ));
165
- return new ArrayDeque <> ();
178
+ return new TriggerStates ();
166
179
}
167
180
168
181
public record TransactionCleanUp (Txn txn , Consumer <Txn > consumer ) implements TxnListener {
@@ -177,6 +190,36 @@ public void abort() {
177
190
}
178
191
}
179
192
193
+ public static final class TriggerStates extends WeakReference <Deque <TriggerState >> {
194
+ public TriggerStates () {
195
+ super (new ArrayDeque <>());
196
+ }
197
+
198
+ public Iterator <TriggerState > descendingIterator () {
199
+ return get ().descendingIterator ();
200
+ }
201
+
202
+ public boolean isEmpty () {
203
+ return get ().isEmpty ();
204
+ }
205
+
206
+ public int size () {
207
+ return get ().size ();
208
+ }
209
+
210
+ public Iterator <TriggerState > iterator () {
211
+ return get ().iterator ();
212
+ }
213
+
214
+ public TriggerState peekFirst () {
215
+ return get ().peekFirst ();
216
+ }
217
+
218
+ public void addFirst (TriggerState newState ) {
219
+ get ().addFirst (newState );
220
+ }
221
+ }
222
+
180
223
public record TriggerState (Trigger trigger , TriggerPhase triggerPhase , TriggerEvent triggerEvent , XmldbURI src ,
181
224
@ Nullable XmldbURI dst , boolean possiblyCyclic ) {
182
225
0 commit comments