2009-02-19 17:24:46 +01:00
// serverAccessTracker.java
// -------------------------------------
// (C) 2009 by Michael Peter Christen; mc@yacy.net
// first published on http://yacy.net
// Frankfurt, Germany, 20.02.2009
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2012-09-21 15:48:16 +02:00
package net.yacy.server ;
2009-02-19 17:24:46 +01:00
2010-09-17 01:00:07 +02:00
import java.util.Collection ;
2009-02-19 17:24:46 +01:00
import java.util.Iterator ;
import java.util.Map ;
2010-09-20 01:00:24 +02:00
import java.util.NoSuchElementException ;
2012-02-27 00:42:32 +01:00
import java.util.Queue ;
2009-02-19 17:24:46 +01:00
import java.util.concurrent.ConcurrentHashMap ;
2012-02-27 00:42:32 +01:00
import java.util.concurrent.LinkedBlockingQueue ;
2009-02-19 17:24:46 +01:00
2014-01-05 05:04:28 +01:00
import net.yacy.cora.protocol.Domains ;
2009-02-19 17:24:46 +01:00
public class serverAccessTracker {
2010-01-11 00:09:48 +01:00
private static final long cleanupCycle = 60000 ; // 1 minute
2014-01-05 05:04:28 +01:00
private static long maxTrackingTime = 3600000 ;
private static int maxTrackingCount = 1000 ;
private static int maxHostCount = 100 ;
private static final ConcurrentHashMap < String , Queue < Track > > accessTracker = new ConcurrentHashMap < String , Queue < Track > > ( ) ; // mappings from requesting host to an ArrayList of serverTrack-entries
private static long lastCleanup ;
private static long lastLocalhostAccess = 0 ;
2011-08-03 20:47:43 +02:00
2010-04-14 18:18:04 +02:00
public static class Track {
2011-08-03 20:47:43 +02:00
private final long time ;
private final String path ;
public Track ( final long time , final String path ) {
2010-04-14 18:18:04 +02:00
this . time = time ;
this . path = path ;
}
public long getTime ( ) {
return this . time ;
}
public String getPath ( ) {
return this . path ;
}
}
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
public static void init ( final long mtt , final int mtc , final int mthc ) {
maxTrackingTime = mtt ;
maxTrackingCount = mtc ;
maxHostCount = mthc ;
2009-02-19 17:24:46 +01:00
}
2011-08-03 20:47:43 +02:00
2009-02-19 17:24:46 +01:00
/ *
* remove all entries from the access tracker where the age of the last access is greater than the given timeout
* /
2014-01-05 05:04:28 +01:00
private static void cleanupAccessTracker ( ) {
2009-02-19 17:24:46 +01:00
2014-01-05 05:04:28 +01:00
if ( System . currentTimeMillis ( ) - lastCleanup < cleanupCycle ) return ; // avoid too many scans of the queues
lastCleanup = System . currentTimeMillis ( ) ;
2011-08-03 20:47:43 +02:00
2009-02-19 17:24:46 +01:00
// clear entries which had no entry for the maxTrackingTime time
2014-01-05 05:04:28 +01:00
final Iterator < Map . Entry < String , Queue < Track > > > i = accessTracker . entrySet ( ) . iterator ( ) ;
2012-02-27 00:42:32 +01:00
Queue < Track > track ;
2009-02-19 17:24:46 +01:00
while ( i . hasNext ( ) ) {
track = i . next ( ) . getValue ( ) ;
2010-09-20 01:00:24 +02:00
clearTooOldAccess ( track ) ;
if ( track . isEmpty ( ) ) {
2009-02-19 17:24:46 +01:00
// all entries are too old. delete the whole track
i . remove ( ) ;
} else {
// check if the maxTrackingCount is exceeded
2014-01-05 05:04:28 +01:00
while ( track . size ( ) > maxTrackingCount ) try {
2009-02-19 17:24:46 +01:00
// delete the oldest entries
2010-09-20 01:00:24 +02:00
track . remove ( ) ;
2011-08-03 20:47:43 +02:00
} catch ( final NoSuchElementException e ) { break ; } // concurrency may cause that the track is already empty
2009-02-19 17:24:46 +01:00
}
}
2011-08-03 20:47:43 +02:00
2009-02-19 17:24:46 +01:00
// if there are more entries left than maxTrackingCount, delete some.
2014-01-05 05:04:28 +01:00
while ( accessTracker . size ( ) > maxHostCount ) {
2009-02-19 17:24:46 +01:00
// delete just any
2014-01-05 05:04:28 +01:00
final String key = accessTracker . keys ( ) . nextElement ( ) ;
2010-09-20 01:00:24 +02:00
if ( key = = null ) break ; // may occur because of concurrency effects
2014-01-05 05:04:28 +01:00
accessTracker . remove ( key ) ;
2009-02-19 17:24:46 +01:00
}
2010-09-20 01:00:24 +02:00
}
2009-02-19 17:24:46 +01:00
2010-09-20 01:00:24 +02:00
/ * *
* compute the number of accesses to a given host in the latest time
* @param host the host that was accessed
* @param delta the time delta from now to the past where the access times shall be computed
* @return the number of accesses to the host in the given time span
* /
2014-01-05 05:04:28 +01:00
public static int latestAccessCount ( final String host , final long delta ) {
2011-08-03 20:47:43 +02:00
final Collection < Track > timeList = accessTrack ( host ) ;
2010-09-25 23:10:50 +02:00
if ( timeList = = null ) return 0 ;
2011-08-03 20:47:43 +02:00
final long time = System . currentTimeMillis ( ) - delta ;
2010-09-20 01:00:24 +02:00
int c = 0 ;
2011-08-03 20:47:43 +02:00
for ( final Track l : timeList ) if ( l ! = null & & l . getTime ( ) > time ) c + + ;
2010-09-20 01:00:24 +02:00
return c ;
2009-02-19 17:24:46 +01:00
}
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
private static void clearTooOldAccess ( final Queue < Track > access ) {
final long time = System . currentTimeMillis ( ) - maxTrackingTime ;
2011-08-03 20:47:43 +02:00
final Iterator < Track > e = access . iterator ( ) ;
2010-09-20 01:00:24 +02:00
Track l ;
2011-08-03 20:47:43 +02:00
int max = access . size ( ) ; // ensure termination
while ( e . hasNext ( ) & & max - - > 0 ) {
2010-09-20 01:00:24 +02:00
l = e . next ( ) ;
if ( l . getTime ( ) < = time ) e . remove ( ) ;
2009-05-26 17:03:50 +02:00
}
2009-02-19 17:24:46 +01:00
}
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
public static void track ( final String host , String accessPath ) {
2009-02-19 17:24:46 +01:00
// check storage size
2014-01-05 05:04:28 +01:00
if ( System . currentTimeMillis ( ) - lastCleanup > cleanupCycle ) {
2010-09-17 01:00:07 +02:00
cleanupAccessTracker ( ) ;
2010-09-19 22:57:25 +02:00
}
2011-08-03 20:47:43 +02:00
2009-02-19 17:24:46 +01:00
// learn that a specific host has accessed a specific path
if ( accessPath = = null ) accessPath = " NULL " ;
2014-01-05 05:04:28 +01:00
Queue < Track > track = accessTracker . get ( host ) ;
2010-09-20 01:00:24 +02:00
if ( track = = null ) {
2012-02-27 00:42:32 +01:00
track = new LinkedBlockingQueue < Track > ( ) ;
2010-09-20 01:00:24 +02:00
track . add ( new Track ( System . currentTimeMillis ( ) , accessPath ) ) ;
// add to tracker
2014-01-05 05:04:28 +01:00
accessTracker . put ( host , track ) ;
2010-09-20 01:00:24 +02:00
} else {
track . add ( new Track ( System . currentTimeMillis ( ) , accessPath ) ) ;
clearTooOldAccess ( track ) ;
}
2014-01-05 05:04:28 +01:00
if ( Domains . isLocalhost ( host ) ) lastLocalhostAccess = System . currentTimeMillis ( ) ;
2009-02-19 17:24:46 +01:00
}
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
public static Collection < Track > accessTrack ( final String host ) {
2009-02-19 17:24:46 +01:00
// returns mapping from Long(accesstime) to path
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
final Queue < Track > access = accessTracker . get ( host ) ;
2009-02-19 17:24:46 +01:00
if ( access = = null ) return null ;
// clear too old entries
2010-09-20 01:00:24 +02:00
clearTooOldAccess ( access ) ;
if ( access . isEmpty ( ) ) {
2014-01-05 05:04:28 +01:00
accessTracker . remove ( host ) ;
2009-02-19 17:24:46 +01:00
}
return access ;
}
2011-08-03 20:47:43 +02:00
2014-01-05 05:04:28 +01:00
public static Iterator < String > accessHosts ( ) {
2009-02-19 17:24:46 +01:00
// returns an iterator of hosts in tracker (String)
2012-02-27 00:42:32 +01:00
final Map < String , Queue < Track > > accessTrackerClone = new ConcurrentHashMap < String , Queue < Track > > ( ) ;
2014-01-05 05:04:28 +01:00
accessTrackerClone . putAll ( accessTracker ) ;
2009-02-19 17:24:46 +01:00
return accessTrackerClone . keySet ( ) . iterator ( ) ;
}
2014-01-05 05:04:28 +01:00
public static long timeSinceAccessFromLocalhost ( ) {
return System . currentTimeMillis ( ) - lastLocalhostAccess ;
}
2009-02-19 17:24:46 +01:00
}