/**
* Copyright 2013 Benjamin Lerer
*
* 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 io.horizondb.db;
import io.horizondb.db.commitlog.ReplayPosition;
import io.horizondb.db.databases.DatabaseManager;
import io.horizondb.db.databases.DatabaseManagerCache;
import io.horizondb.db.databases.OnDiskDatabaseManager;
import io.horizondb.db.operations.Operations;
import io.horizondb.db.series.OnDiskTimeSeriesManager;
import io.horizondb.db.series.OnDiskTimeSeriesPartitionManager;
import io.horizondb.db.series.TimeSeriesManager;
import io.horizondb.db.series.TimeSeriesManagerCache;
import io.horizondb.db.series.TimeSeriesPartitionManager;
import io.horizondb.db.series.TimeSeriesPartitionManagerCaches;
import io.horizondb.io.ReadableBuffer;
import io.horizondb.model.ErrorCodes;
import io.horizondb.model.protocol.Msg;
import io.horizondb.model.protocol.Msgs;
import io.horizondb.model.protocol.OpCode;
import java.io.IOException;
import com.codahale.metrics.MetricRegistry;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
/**
* The default implementation for the <code>StorageEngine</code>.
*/
public class DefaultStorageEngine extends AbstractComponent implements StorageEngine {
/**
* The database manager.
*/
private final DatabaseManager databaseManager;
/**
* The builder used to build the operation context.
*/
private final OperationContext.Builder contextBuilder;
public DefaultStorageEngine(Configuration configuration) {
TimeSeriesPartitionManager partitionManager = new TimeSeriesPartitionManagerCaches(configuration,
new OnDiskTimeSeriesPartitionManager(configuration));
TimeSeriesManager seriesManager = new TimeSeriesManagerCache(configuration,
new OnDiskTimeSeriesManager(partitionManager,
configuration));
this.databaseManager = new DatabaseManagerCache(configuration, new OnDiskDatabaseManager(configuration,
seriesManager));
this.contextBuilder = OperationContext.newBuilder(this.databaseManager);
}
/**
* {@inheritDoc}
*/
@Override
public DatabaseManager getDatabaseManager() {
return this.databaseManager;
}
/**
* {@inheritDoc}
*/
@Override
public void register(MetricRegistry registry) {
register(registry, this.databaseManager);
}
/**
* {@inheritDoc}
*/
@Override
public void unregister(MetricRegistry registry) {
unregister(registry, this.databaseManager);
}
/**
* {@inheritDoc}
*/
@Override
protected void doStart() throws IOException, InterruptedException {
start(this.databaseManager);
this.contextBuilder.replay(false);
}
/**
* {@inheritDoc}
*/
@Override
protected void doShutdown() throws InterruptedException {
shutdown(this.databaseManager);
}
/**
* {@inheritDoc}
*/
@Override
public Object execute(Msg<?> request, ListenableFuture<ReplayPosition> future) throws IOException, HorizonDBException {
this.contextBuilder.future(future);
OpCode opCode = request.getOpCode();
Operation operation = Operations.getOperationFor(opCode);
if (operation == null) {
String message = String.format("The operation code message %s is unknown.", opCode);
this.logger.error(message);
return Msgs.newErrorMsg(request.getHeader(), ErrorCodes.UNKNOWN_OPERATION_CODE, message);
}
OperationContext context = this.contextBuilder.build();
return operation.perform(context, request);
}
/**
* {@inheritDoc}
*/
@Override
public ListenableFuture<Boolean> forceFlush(long id) throws InterruptedException {
TimeSeriesManager timeSeriesManager = this.databaseManager.getTimeSeriesManager();
TimeSeriesPartitionManager partitionManager = timeSeriesManager.getPartitionManager();
return partitionManager.forceFlush(id);
}
/**
* {@inheritDoc}
*/
@Override
public void replay(ReplayPosition replayPosition, ReadableBuffer bytes) throws IOException {
try {
Msg<?> request = Msg.parseFrom(bytes);
this.contextBuilder.replay(true);
execute(request, Futures.immediateFuture(replayPosition));
} catch (HorizonDBException e) {
this.logger.warn("The following exception has occured during commit log replay: ", e);
}
}
}