/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* 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 scouter.util;
public abstract class MeteringUtil<T> {
protected final int BUCKET_SIZE;
protected final int TIME_UNIT;
public MeteringUtil() {
this(1000,301);
}
public MeteringUtil(int bucketSize) {
this(1000,bucketSize);
}
public MeteringUtil(int timeUnit, int bucketSize) {
this.TIME_UNIT=timeUnit;
this.BUCKET_SIZE = bucketSize;
this._time_ = getTime();
this._pos_ = (int) (_time_ % BUCKET_SIZE);
this.table = new Object[bucketSize];
for (int i = 0; i < bucketSize; i++) {
this.table[i] = create();
}
}
private final Object[] table;
private long _time_;
private int _pos_;
abstract protected T create();
abstract protected void clear(T o);
public synchronized T getCurrentBucket() {
int pos = getPosition();
return (T)table[pos];
}
public synchronized int getPosition() {
long curTime = getTime();
if (curTime != _time_) {
for (int i = 0; i < (curTime - _time_) && i < BUCKET_SIZE; i++) {
_pos_ = (_pos_ + 1 > BUCKET_SIZE - 1) ? 0 : _pos_ + 1;
clear((T)table[_pos_]);
}
_time_ = curTime;
_pos_ = (int) (_time_ % BUCKET_SIZE);
}
return _pos_;
}
protected int check(int period) {
if (period >= BUCKET_SIZE)
period = BUCKET_SIZE - 1;
return period;
}
protected int stepback(int pos) {
if (pos == 0)
pos = BUCKET_SIZE - 1;
else
pos--;
return pos;
}
public static interface Handler<T> {
public void process(T u);
}
public int search(int period, Handler<T> h) {
period = check(period);
int pos = getPosition();
for (int i = 0; i < period; i++, pos = stepback(pos)) {
h.process((T)table[pos]);
}
return period;
}
public T[] search(int period) {
period = check(period);
int pos = getPosition();
T[] out = (T[]) new Object[period];
for (int i = 0; i < period; i++, pos = stepback(pos)) {
out[i]=((T)table[pos]);
}
return out;
}
protected long getTime() {
return System.currentTimeMillis() / TIME_UNIT;
}
}