com.kolibrifx.plovercrest.server.internal.EngineAdapter Maven / Gradle / Ivy
Show all versions of plovercrest-server Show documentation
/*
* Copyright (c) 2010-2017, KolibriFX AS. Licensed under the Apache License, version 2.0.
*/
package com.kolibrifx.plovercrest.server.internal;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicBoolean;
import com.kolibrifx.plovercrest.client.PlovercrestTableNotFound;
import com.kolibrifx.plovercrest.client.RangeQuery;
import com.kolibrifx.plovercrest.client.TableMetadata;
import com.kolibrifx.plovercrest.server.TableInfo;
import com.kolibrifx.plovercrest.server.internal.protocol.ReadContinuationCache;
import com.kolibrifx.plovercrest.server.internal.streams.RangeReadInfo;
import com.kolibrifx.plovercrest.server.internal.streams.RangeStreamUtils;
import com.kolibrifx.plovercrest.server.internal.streams.RuntimeReadContinuation;
import com.kolibrifx.plovercrest.server.streams.ReaderPosition;
import com.kolibrifx.plovercrest.server.streams.Stream;
import com.kolibrifx.plovercrest.server.streams.StreamEngine;
import com.kolibrifx.plovercrest.server.streams.StreamInfo;
/**
* Helper class for {@link com.kolibrifx.plovercrest.server.internal.protocol.StreamConnection}.
* Adapts some {@link StreamEngine} functionality to the plovercrest protocol, and provides wrappers
* that throw exceptions for missing tables/streams.
*
* Note: this (and StreamConnection itself) should ideally be split into smaller utility classes.
*/
public class EngineAdapter {
//private static final Logger log = Logger.getLogger(EngineAdapter.class);
public interface ChunkedDataHandler extends OverflowHandler {
void writeRemainingData();
}
/**
* Common parameters for the different read functions.
*/
public static class ReadRequest {
private final ReadContinuationCache cache;
private final String name;
private final int maxCount;
private final ByteBuffer targetBuffer;
private final ChunkedDataHandler dataHandler;
private final AtomicBoolean timedOut;
public ReadRequest(final ReadContinuationCache cache,
final String name,
final int maxCount,
final ByteBuffer targetBuffer,
final ChunkedDataHandler dataHandler,
final AtomicBoolean timedOut) {
this.cache = cache;
this.name = name;
this.maxCount = maxCount;
this.targetBuffer = targetBuffer;
this.dataHandler = dataHandler;
this.timedOut = timedOut;
}
}
private final StreamEngine streamEngine;
public EngineAdapter(final StreamEngine streamEngine) {
this.streamEngine = streamEngine;
}
private void putTrailer(final ByteBuffer buffer, final long trailer, final ReaderPosition position,
final boolean isAtEndOfRange) {
buffer.putLong(trailer);
buffer.putInt(ReaderPositionUtils.getTag(position.getPositionType()));
buffer.putLong(position.getTimestampOrIndex());
buffer.putInt(position.getSkipCount());
buffer.put((byte) (isAtEndOfRange ? 1 : 0));
}
public void read(final ReadRequest request, final RangeQuery rangeQuery) {
final Stream stream = openOrThrow(request.name);
final ByteBufferStreamObserver observer =
new ByteBufferStreamObserver(request.targetBuffer, request.dataHandler);
final RuntimeReadContinuation continuation =
RangeStreamUtils.readRange(stream, request.maxCount, rangeQuery, observer, request.timedOut);
final RangeReadInfo info = continuation.getInfo();
finishRead(request, continuation, info);
}
public void readContinue(final ReadRequest request, final RangeQuery.RangeType rangeType,
final long endTimestampOrIndex, final ReaderPosition readerPosition) {
final ByteBufferStreamObserver observer =
new ByteBufferStreamObserver(request.targetBuffer, request.dataHandler);
final RuntimeReadContinuation continuation =
request.cache.tryGetAndRemove(request.name, readerPosition);
final RangeReadInfo info;
if (continuation != null) {
continuation.getObserver().setWrappedObserver(observer);
info =
RangeStreamUtils.doRead(continuation.getReader(), request.maxCount, continuation.getObserver(),
request.timedOut).getInfo();
} else {
final Stream stream = openOrThrow(request.name);
info =
RangeStreamUtils.continueReadRange(stream, request.maxCount, rangeType, endTimestampOrIndex,
observer, readerPosition, request.timedOut);
}
finishRead(request, continuation, info);
}
private void finishRead(final ReadRequest request, final RuntimeReadContinuation continuation,
final RangeReadInfo info) {
request.dataHandler.writeRemainingData();
// trailer: last valid timestamp, and the reader index (continuation)
// if the end has been reached, the "last valid timestamp". Otherwise, -1.
final long trailer = info.isAtEndOfStream() ? info.getLastValidTimestamp() : -1;
putTrailer(request.targetBuffer, trailer, info.getPosition(), info.isAtEndOfRange());
if (!info.isAtEndOfRange()) {
request.cache.register(request.name, continuation);
}
}
public Stream open(final String name) {
return streamEngine.openRaw(name);
}
public Stream openOrThrow(final String name) {
final Stream s = open(name);
if (s == null) {
throw new PlovercrestTableNotFound("Table not found: " + name);
}
return s;
}
public void readStreamInfo(final String tableName, final ByteBuffer buffer) {
final Stream t = openOrThrow(tableName);
buffer.putLong(t.getFirstTimestamp());
buffer.putLong(t.getLastTimestamp());
buffer.putLong(t.getLastValidTimestamp());
buffer.putLong(t.getDataLengthInBytes());
buffer.putLong(t.getEntryCount());
final byte frozen = (byte) (t.isFrozen() ? 1 : 0);
buffer.put(frozen);
}
public void write(final String tableName, final long timestamp, final ByteBuffer buf) {
openOrThrow(tableName).getWriter().write(timestamp, buf);
}
public void freeze(final String tableName) {
openOrThrow(tableName).getWriter().freeze();
}
public void unfreeze(final String tableName) {
openOrThrow(tableName).getWriter().unfreeze();
}
public Collection list() {
return streamEngine.list();
}
public StreamEngine getStreamEngine() {
return streamEngine;
}
public TableMetadata getMetadata(final String name) {
final Stream stream = streamEngine.openRaw(name);
if (stream == null) {
return null;
} else {
return stream.getMetadata();
}
}
public void flush(final String tableName) {
openOrThrow(tableName).getWriter().flush();
}
public void create(final TableInfo info) {
streamEngine.create(info);
}
public boolean delete(final String tableName) {
return streamEngine.delete(tableName);
}
public boolean rename(final String oldName, final String newName) {
return streamEngine.rename(oldName, newName);
}
}