001/** 002 * The MIT License (MIT) 003 * 004 * Copyright (c) 2019 nobark (tools4j), Marco Terzer, Anton Anufriev 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in all 014 * copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 022 * SOFTWARE. 023 */ 024package org.tools4j.nobark.queue; 025 026import java.util.function.Supplier; 027 028/** 029 * A listener for an {@link ConflationQueue.Appender appender} of a {@link ConflationQueue} for instance useful to 030 * record performance metrics related to enqueue operations. The listener or a supplier thereof is usually passed to 031 * the constructor of a conflation queue. Note that listeners must be thread safe if used in a multi-producer 032 * environment; best practice is to use separate listener instances for each producer thread e.g. by using 033 * {@link #threadLocal(Supplier)} or {@link #threadLocalSupplier(Supplier)}. 034 * 035 * @param <K> the type of the conflation key 036 * @param <V> the type of values in the queue 037 */ 038@FunctionalInterface 039public interface AppenderListener<K,V> { 040 /** 041 * The type of conflation that occurred when an element was enqueued. 042 */ 043 enum Conflation { 044 /** 045 * No conflation occurred, that is, no other value with the same conflation key exists in the queue at the 046 * time of enqueueing the value. 047 */ 048 UNCONFLATED, 049 /** 050 * Conflation occurred and the existing old value present in the queue was evicted and replaced by the newly 051 * enqueued value. 052 */ 053 EVICTED, 054 /** 055 * Conflation occurred and the existing old element present in the queue was merged with the newly enqueued 056 * element via a {@link Merger}; the result of the merge operation is the value in the queue now. 057 */ 058 MERGED 059 } 060 061 /** 062 * Called whenever a value is {@link ConflationQueue.Appender#enqueue(Object, Object) enqueued}. 063 * 064 * @param queue the conflation queue, sometimes useful to record queue size metrics, never null 065 * @param key the conflation key, never null 066 * @param newValue the value that has been enqueued (the merged value if conflation==MERGED), never null 067 * @param oldValue the old value that is replaced, unless conflation=UNCONFLATED in which case old value is 068 * either null or the exchange value in case of an {@link ExchangeConflationQueue} 069 * @param conflation the type of conflation that has occurred, if any 070 */ 071 void enqueued(ConflationQueue<? extends K, ? extends V> queue, K key, V newValue, V oldValue, Conflation conflation); 072 073 /** 074 * Constant for a no-op listener. 075 */ 076 AppenderListener<Object,Object> NOOP = (q, k, v, o, c) -> {}; 077 078 /** 079 * Creates an appender listener that delegates to thread-local listener instances created on demand by the given 080 * supplier. This listener can be passed to the constructors of {@link AtomicConflationQueue} which use a single 081 * appender instance for all producer threads. 082 * 083 * @param listenerSupplier the supplier acting as factory for per-thread listener instances 084 * @param <K> the type of the conflation key 085 * @param <V> the type of values in the queue 086 * @return a listener that delegates to thread-local listener instances 087 */ 088 static <K,V> AppenderListener<K,V> threadLocal(final Supplier<? extends AppenderListener<K,V>> listenerSupplier) { 089 final ThreadLocal<AppenderListener<K,V>> threadLocal = ThreadLocal.withInitial(listenerSupplier); 090 return (q,k,v,o,c) -> threadLocal.get().enqueued(q,k,v,o,c); 091 } 092 093 /** 094 * Creates a thread local supplier that creates a new instance once for every caller thread. This listener can be 095 * passed to the constructors of {@link EvictConflationQueue} and {@link MergeConflationQueue} which use a per 096 * thread appender instances; the returned supplier will create a new thread-local listener instance for every 097 * appender instance that is created. 098 * 099 * @param listenerSupplier the supplier acting as factory for per-thread listener instances 100 * @param <L> the appender listener (sub-)type 101 * @return a supplier creating thread-local listener instances 102 */ 103 static <L extends AppenderListener<?,?>> Supplier<L> threadLocalSupplier(final Supplier<L> listenerSupplier) { 104 return ThreadLocal.withInitial(listenerSupplier)::get; 105 } 106}