/**
* AnalyzerBeans
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.analyzer.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.metamodel.util.Action;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provides a buffering mechanism that enables writing rows periodically instead
* of instantly.
*/
public class WriteBuffer {
private static final Logger logger = LoggerFactory.getLogger(WriteBuffer.class);
private final BlockingQueue<Object[]> _buffer;
private final Action<Iterable<Object[]>> _flushAction;
private final AtomicInteger _batchNumber;
public WriteBuffer(int bufferSize, Action<Iterable<Object[]>> flushAction) {
if (bufferSize <= 0) {
throw new IllegalArgumentException("Buffer size must be a positive integer");
}
_batchNumber = new AtomicInteger();
_buffer = new ArrayBlockingQueue<Object[]>(bufferSize);
_flushAction = flushAction;
}
protected Queue<Object[]> getBuffer() {
return _buffer;
}
public final void addToBuffer(Object[] rowData) {
while (!_buffer.offer(rowData)) {
flushBuffer();
}
}
public final void flushBuffer() {
int flushSize = _buffer.size();
if (flushSize == 0) {
return;
}
logger.info("Flushing {} rows in write buffer", flushSize);
final List<Object[]> copy = new ArrayList<Object[]>(flushSize);
_buffer.drainTo(copy, flushSize);
if (copy.isEmpty()) {
// this can happen when there's a race going on for flushing the
// buffer concurrently.
return;
}
try {
int batchNo = _batchNumber.incrementAndGet();
logger.info("Write batch no. {} starting", batchNo);
_flushAction.run(copy);
logger.info("Write batch no. {} finished", batchNo);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new IllegalStateException(e);
}
}
}