class ReadLockWithTracking extends ReentrantReadWriteLock.ReadLock {
        /** */
        private static final long serialVersionUID = 0L;

        /** */
        private static final ThreadLocal<T2<Integer, Long>> READ_LOCK_HOLDER_TS =
            ThreadLocal.withInitial(() -> new T2<>(0, 0L));

        /** */
        private IgniteLogger log;

        /** */
        private long readLockThreshold;

        /** */
        protected ReadLockWithTracking(ReentrantReadWriteLock lock, @Nullable IgniteLogger log, long readLockThreshold) {
            super(lock);

            this.log = log;

            this.readLockThreshold = readLockThreshold;
        }

        /** */
        private void inc() {
            T2<Integer, Long> val = READ_LOCK_HOLDER_TS.get();

            int cntr = val.get1();

            if (cntr == 0)
                val.set2(U.currentTimeMillis());

            val.set1(++cntr);

            READ_LOCK_HOLDER_TS.set(val);
        }

        /** */
        private void dec() {<FILL_FUNCTION_BODY>}

        /** {@inheritDoc} */
        @Override public void lock() {
            super.lock();

            inc();
        }

        /** {@inheritDoc} */
        @Override public void lockInterruptibly() throws InterruptedException {
            super.lockInterruptibly();

            inc();
        }

        /** {@inheritDoc} */
        @Override public boolean tryLock() {
            if (super.tryLock()) {
                inc();

                return true;
            }
            else
                return false;
        }

        /** {@inheritDoc} */
        @Override public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
            if (super.tryLock(timeout, unit)) {
                inc();

                return true;
            }
            else
                return false;
        }

        /** {@inheritDoc} */
        @Override public void unlock() {
            super.unlock();

            dec();
        }
    }

            T2<Integer, Long> val = READ_LOCK_HOLDER_TS.get();

            int cntr = val.get1();

            if (--cntr == 0) {
                long timeout = U.currentTimeMillis() - val.get2();

                if (timeout > readLockThreshold) {
                    GridStringBuilder sb = new GridStringBuilder();

                    sb.a(LOCK_HOLD_MESSAGE + timeout + " ms." + nl());

                    U.printStackTrace(Thread.currentThread().getId(), sb);

                    U.warn(log, sb.toString());
                }
            }

            val.set1(cntr);

            READ_LOCK_HOLDER_TS.set(val);
        
<no_super_class>