package org.araqne.logdb.query.command; import java.util.concurrent.atomic.AtomicLong; import org.araqne.cron.AbstractTickTimer; import org.araqne.cron.TickService; import org.araqne.logdb.QueryCommand; import org.araqne.logdb.QueryStopReason; import org.araqne.logdb.Row; import org.araqne.logdb.RowBatch; import org.araqne.logdb.ThreadSafe; public class RateLimit extends QueryCommand implements ThreadSafe { private TickService tickService; private CounterReset reset; private AtomicLong counter = new AtomicLong(); private int limit; private boolean splitRowBatch; private int delay; public RateLimit(TickService tickService, int limit, boolean splitRowBatch, int delay) { this.tickService = tickService; this.limit = limit; this.splitRowBatch = splitRowBatch; this.delay = delay; } @Override public String getName() { return "ratelimit"; } @Override public void onPush(Row row) { long count = counter.incrementAndGet(); if (count >= limit) { synchronized (counter) { try { while (counter.get() >= limit) counter.wait(10); } catch (InterruptedException e) { } } } pushPipe(row); } @Override public void onPush(RowBatch rowBatch) { if (splitRowBatch) { super.onPush(rowBatch); } else { long count = counter.addAndGet(rowBatch.size); if (count >= limit) { synchronized (counter) { try { while (counter.get() >= limit) counter.wait(10); } catch (InterruptedException e) { } } } pushPipe(rowBatch); } } @Override public void onStart() { reset = new CounterReset(); tickService.addTimer(reset); } @Override public void onClose(QueryStopReason reason) { if (reset != null) tickService.removeTimer(reset); } @Override public String toString() { return "ratelimit " + limit; } private class CounterReset extends AbstractTickTimer { @Override public int getInterval() { return delay; } @Override public void onTick() { counter.set(0); } } }