2626import org .exist .xmldb .XmldbURI ;
2727
2828import javax .annotation .Nullable ;
29+ import java .lang .ref .WeakReference ;
2930import java .util .ArrayDeque ;
31+ import java .util .Collections ;
3032import java .util .Deque ;
3133import java .util .Iterator ;
34+ import java .util .Map ;
3235import java .util .Objects ;
33- import java .util .concurrent .ConcurrentHashMap ;
34- import java .util .concurrent .ConcurrentMap ;
36+ import java .util .WeakHashMap ;
3537import java .util .function .BiConsumer ;
3638import java .util .function .Consumer ;
3739
4244 * @author <a href="mailto:[email protected] ">Adam Retter</a> 4345 */
4446public 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 <>());
4748
4849 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 );
5051
5152 if (states .isEmpty ()) {
5253 if (triggerPhase != TriggerPhase .BEFORE ) {
@@ -123,7 +124,7 @@ public static void clearIfFinished(final Txn txn, final TriggerPhase phase) {
123124 if (phase == TriggerPhase .AFTER ) {
124125
125126 int depth = 0 ;
126- final Deque < TriggerState > states = getStates (txn );
127+ final TriggerStates states = getStates (txn );
127128 for (final Iterator <TriggerState > it = states .descendingIterator (); it .hasNext (); ) {
128129 final TriggerState state = it .next ();
129130 switch (state .triggerPhase ) {
@@ -144,25 +145,37 @@ public static void clearIfFinished(final Txn txn, final TriggerPhase phase) {
144145 }
145146 }
146147
148+ public static int keys () {
149+ return TRIGGER_STATES .size ();
150+ }
151+
152+ public static void clearAll () {
153+ TRIGGER_STATES .clear ();
154+ }
155+
147156 public static void clear (final Txn txn ) {
148- TRIGGER_STATES .remove (txn );
157+ TRIGGER_STATES .remove (Thread . currentThread () );
149158 }
150159
151160 public static boolean isEmpty (final Txn txn ) {
152161 return getStates (txn ).isEmpty ();
153162 }
154163
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 ) {
156169 TRIGGER_STATES .forEach (action );
157170 }
158171
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 () );
161174 }
162175
163- private static Deque < TriggerState > initStates (final Txn txn ) {
176+ private static TriggerStates initStates (final Txn txn ) {
164177 txn .registerListener (new TransactionCleanUp (txn , TriggerStatePerThread ::clear ));
165- return new ArrayDeque <> ();
178+ return new TriggerStates ();
166179 }
167180
168181 public record TransactionCleanUp (Txn txn , Consumer <Txn > consumer ) implements TxnListener {
@@ -177,6 +190,36 @@ public void abort() {
177190 }
178191 }
179192
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+
180223 public record TriggerState (Trigger trigger , TriggerPhase triggerPhase , TriggerEvent triggerEvent , XmldbURI src ,
181224 @ Nullable XmldbURI dst , boolean possiblyCyclic ) {
182225
0 commit comments