/*
* Copyright 2013 Eediom Inc.
*
* 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 org.araqne.logstorage;
import java.util.List;
public abstract class LogTraverseCallback {
public enum BlockSkipReason {
Reserved, Fixed
}
private final Sink sink;
private Throwable failure;
abstract public void interrupt();
abstract public boolean isInterrupted();
public boolean isEof() {
return sink.isEof() || isInterrupted();
}
public LogTraverseCallback(Sink sink) {
this.sink = sink;
}
public boolean isOrdered() {
return sink.isOrdered();
}
public void writeLogs(List<Log> logs) {
if (!isInterrupted())
sink.write(filter(logs));
}
public boolean isFailed() {
return failure != null;
}
public void setFailure(Throwable t) {
failure = t;
}
public Throwable getFailure() {
return failure;
}
abstract protected List<Log> filter(List<Log> logs);
public static abstract class Sink {
private final long offset;
private final long limit;
private final boolean ordered;
/** guarded by this */
private long curr;
/** guarded by this */
private boolean eof;
public Sink(long offset, long limit) {
this(offset, limit, true);
}
/** if ordered can be false, processLogs() and onBlockSkipped() should be thread-safe. */
public Sink(long offset, long limit, boolean order) {
this.offset = offset;
this.limit = limit;
this.ordered = order;
this.curr = 0;
this.eof = false;
}
public synchronized boolean isEof() {
return eof;
}
public boolean isOrdered() {
return ordered;
}
/**
* @param logs
* @return true when it is not closed
* false when it is closed
*/
public boolean write(List<Log> logs) {
if (logs.isEmpty())
return !isEof();
int processEnd = logs.size();
int cnt = logs.size();
long start = -1;
long end = -1;
synchronized (this) {
if (eof)
return false;
start = curr;
end = curr += cnt;
if (limit > 0 && end >= offset + limit) {
processEnd = (int) (offset + limit - start);
eof = true;
}
}
if (offset > 0 && end <= offset)
return true;
int processBegin = 0;
if (offset > 0 && start <= offset) {
processBegin = (int) (offset - start);
}
if (processBegin == 0 && processEnd == logs.size())
processLogs(logs);
else
processLogs(logs.subList(processBegin, processEnd));
return !isEof();
}
/** this method should be thread-safe if it is used in not-ordered case. */
protected abstract void processLogs(List<Log> logs);
protected void onBlockSkipped(BlockSkipReason reason, long firstId, int logCount) {
}
}
public void onBlockSkipped(BlockSkipReason reason, long firstId, int logCount) {
sink.onBlockSkipped(reason, firstId, logCount);
}
}