/*
   Copyright 2008-2009 Christian Vest Hansen

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package net.nanopool.hooks;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import javax.sql.ConnectionPoolDataSource;

/**
 *
 * @author cvh
 */
public class TimingHook implements Hook {
    private final ReentrantReadWriteLock rwlock;
    private final ReadLock readLock;
    private final WriteLock writeLock;
    private long totalTimeMs = 0;
    private int totalConnects = 0;

    private final ThreadLocal<Long> currentStartTime = new ThreadLocal<Long>();
    private final EventType startType;
    private final EventType endType;

    public TimingHook(EventType timerStartType, EventType timerEndType) {
        this.startType = timerStartType;
        this.endType = timerEndType;
        rwlock = new ReentrantReadWriteLock(true);
        readLock = rwlock.readLock();
        writeLock = rwlock.writeLock();
    }

    public void run(EventType type, ConnectionPoolDataSource source, Connection con, SQLException sqle) {
        if (currentStartTime.get() == null && type == startType) {
            currentStartTime.set(System.nanoTime());
        } else if (type == endType) {
            long end = System.nanoTime();
            long start = currentStartTime.get();
            long spanMs = (end - start) / 1000000L;
            currentStartTime.set(null);
            writeLock.lock();
            try {
                totalTimeMs += spanMs;
                totalConnects++;
            } finally {
                writeLock.unlock();
            }
        }
    }

    public double avgMs() {
        double ms = 0;
        double connects = 0;
        readLock.lock();
        try {
            ms = totalTimeMs;
            connects = totalConnects;
        } finally {
            readLock.unlock();
        }
        return ms / connects;
    }

    public long totalMs() {
        readLock.lock();
        try {
            return totalTimeMs;
        } finally {
            readLock.unlock();
        }
    }

    public int totalConnects() {
        readLock.lock();
        try {
            return totalConnects;
        } finally {
            readLock.unlock();
        }
    }

    public void reset() {
        writeLock.lock();
        try {
            totalConnects = 0;
            totalTimeMs = 0;
        } finally {
            writeLock.unlock();
        }
    }
}

@@ -1489,24 +1489,231 @@
 merEndType;%0A
+        // it is important that this RW-lock is fair, because otherwise readers%0A        // may starve out writers, and that is bad because writers are in the%0A        // process of working with a connection.%0A
         rwlo
@@ -1843,24 +1843,30 @@
 %0A    public 
+final 
 void run(Eve
@@ -2362,24 +2362,18 @@
 otal
-TimeMs += spanMs
+Connects++
 ;%0A  
@@ -2382,39 +2382,48 @@
             
-totalConnects++
+recordTimeMillis(spanMs)
 ;%0A          
@@ -2514,16 +2514,22 @@
  public 
+final 
 double a
@@ -2805,16 +2805,22 @@
  public 
+final 
 long tot
@@ -2978,16 +2978,22 @@
  public 
+final 
 int tota
@@ -3158,16 +3158,22 @@
  public 
+final 
 void res
@@ -3346,11 +3346,100 @@
  %7D%0A    %7D
+%0A%0A    protected void recordTimeMillis(long spanMs) %7B%0A        totalTimeMs += spanMs;%0A    %7D
 %0A%7D%0A

make extending TimingHook safer