├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── antlr4 │ └── io │ │ └── horizondb │ │ └── db │ │ └── parser │ │ └── Hql.g4 ├── assembly │ └── dep.xml ├── config │ └── horizondb-config.properties ├── java │ └── io │ │ └── horizondb │ │ └── db │ │ ├── AbstractComponent.java │ │ ├── Component.java │ │ ├── Configuration.java │ │ ├── ConfigurationLoader.java │ │ ├── DatabaseEngine.java │ │ ├── DefaultDatabaseEngine.java │ │ ├── DefaultStorageEngine.java │ │ ├── HorizonDBException.java │ │ ├── HorizonDBFiles.java │ │ ├── HorizonDbDaemon.java │ │ ├── HorizonServer.java │ │ ├── HorizonServerHandler.java │ │ ├── HqlConverter.java │ │ ├── MsgToByteEncoder.java │ │ ├── Names.java │ │ ├── Operation.java │ │ ├── OperationContext.java │ │ ├── PropertiesFileConfigurationLoader.java │ │ ├── Query.java │ │ ├── QueryContext.java │ │ ├── StorageEngine.java │ │ ├── btree │ │ ├── AbstractBlockOrganizedByteReader.java │ │ ├── AbstractNode.java │ │ ├── AbstractNodeReader.java │ │ ├── AbstractNodeWriter.java │ │ ├── BTree.java │ │ ├── BTreeStore.java │ │ ├── BlockOrganizedFileDataInput.java │ │ ├── BlockOrganizedFileDataOutput.java │ │ ├── BlockOrganizedReadableBuffer.java │ │ ├── BlockPrefixes.java │ │ ├── Constants.java │ │ ├── DataPointer.java │ │ ├── DefaultValueWrapper.java │ │ ├── InMemoryNodeManager.java │ │ ├── InternalNode.java │ │ ├── KeyValueIterator.java │ │ ├── LeafNode.java │ │ ├── Node.java │ │ ├── NodeCache.java │ │ ├── NodeManager.java │ │ ├── NodeProxy.java │ │ ├── NodeReader.java │ │ ├── NodeReaderFactory.java │ │ ├── NodeVisitor.java │ │ ├── NodeWriter.java │ │ ├── NodeWriterFactory.java │ │ ├── OnDiskNodeManager.java │ │ ├── SimpleNodeVisitor.java │ │ ├── ValueProxy.java │ │ └── ValueWrapper.java │ │ ├── cache │ │ ├── AbstractCache.java │ │ ├── AbstractMultilevelCache.java │ │ ├── Cache.java │ │ ├── CallableAdaptor.java │ │ └── ValueLoader.java │ │ ├── commitlog │ │ ├── AbstractWriteExecutor.java │ │ ├── BatchWriteExecutor.java │ │ ├── CommitLog.java │ │ ├── CommitLogAllocator.java │ │ ├── CommitLogSegment.java │ │ ├── CommitLogWriteFutureTask.java │ │ ├── IdFactory.java │ │ ├── PeriodicWriteExecutor.java │ │ ├── ReplayPosition.java │ │ └── WriteExecutor.java │ │ ├── databases │ │ ├── AbstractDatabaseManager.java │ │ ├── Database.java │ │ ├── DatabaseCache.java │ │ ├── DatabaseManager.java │ │ ├── DatabaseManagerCache.java │ │ ├── InMemoryDatabaseManager.java │ │ └── OnDiskDatabaseManager.java │ │ ├── metrics │ │ ├── CacheMetrics.java │ │ ├── Monitorable.java │ │ ├── Nameable.java │ │ ├── PrefixFilter.java │ │ └── ThreadPoolExecutorMetrics.java │ │ ├── operations │ │ ├── ChunkedRecordSet.java │ │ ├── ChunkedRecordStream.java │ │ ├── CreateDatabaseOperation.java │ │ ├── CreateTimeSeriesOperation.java │ │ ├── DropDatabaseOperation.java │ │ ├── DropTimeSeriesOperation.java │ │ ├── InsertOperation.java │ │ ├── Operations.java │ │ ├── SelectOperation.java │ │ └── UseDatabaseOperation.java │ │ ├── parser │ │ ├── BadHqlGrammarException.java │ │ ├── ErrorHandler.java │ │ ├── MsgBuilder.java │ │ ├── QueryParser.java │ │ └── builders │ │ │ ├── CreateDatabaseMsgBuilder.java │ │ │ ├── CreateTimeSeriesMsgBuilder.java │ │ │ ├── DropDatabaseMsgBuilder.java │ │ │ ├── DropTimeSeriesMsgBuilder.java │ │ │ ├── InsertMsgBuilder.java │ │ │ ├── MsgBuilderDispatcher.java │ │ │ ├── PredicateBuilder.java │ │ │ ├── PredicateBuilders.java │ │ │ ├── ProjectionBuilder.java │ │ │ ├── SelectMsgBuilder.java │ │ │ └── UseDatabaseMsgBuilder.java │ │ ├── series │ │ ├── AbstractTimeSeriesManager.java │ │ ├── AbstractTimeSeriesPartitionManager.java │ │ ├── FileMetaData.java │ │ ├── FlushListener.java │ │ ├── FlushManager.java │ │ ├── InMemoryTimeSeriesManager.java │ │ ├── InMemoryTimeSeriesPartitionManager.java │ │ ├── MapKeyValueIterator.java │ │ ├── MemTimeSeries.java │ │ ├── MergingKeyValueIterator.java │ │ ├── OnDiskTimeSeriesManager.java │ │ ├── OnDiskTimeSeriesPartitionManager.java │ │ ├── PartitionId.java │ │ ├── SlabAllocator.java │ │ ├── TimeSeries.java │ │ ├── TimeSeriesCache.java │ │ ├── TimeSeriesElement.java │ │ ├── TimeSeriesElements.java │ │ ├── TimeSeriesFile.java │ │ ├── TimeSeriesId.java │ │ ├── TimeSeriesManager.java │ │ ├── TimeSeriesManagerCache.java │ │ ├── TimeSeriesPartition.java │ │ ├── TimeSeriesPartitionListener.java │ │ ├── TimeSeriesPartitionManager.java │ │ ├── TimeSeriesPartitionManagerCaches.java │ │ ├── TimeSeriesPartitionMetaData.java │ │ ├── TimeSeriesPartitionReadCache.java │ │ ├── TimeSeriesPartitionSecondLevelCache.java │ │ └── TimeSeriesPartitionWriteCache.java │ │ └── util │ │ ├── ArrayUtils.java │ │ └── concurrent │ │ ├── CountDownFuture.java │ │ ├── ExecutorsUtils.java │ │ ├── ForwardingRunnableScheduledFuture.java │ │ ├── FutureUtils.java │ │ ├── LoggingUncaughtExceptionHandler.java │ │ ├── NamedThreadFactory.java │ │ └── SyncTask.java └── scripts │ └── horizondb.bat └── test ├── java └── io │ └── horizondb │ └── db │ ├── PropertiesFileConfigurationLoaderTest.java │ ├── btree │ ├── AssertNodes.java │ ├── BTreeTest.java │ ├── BlockOrganizedFileDataInputTest.java │ ├── BlockOrganizedFileDataOutputTest.java │ ├── IntegerAndStringNodeReader.java │ ├── IntegerAndStringNodeWriter.java │ └── OnDiskNodeManagerTest.java │ ├── commitlog │ ├── CommitLogAllocatorTest.java │ ├── CommitLogSegmentTest.java │ ├── CommitLogTest.java │ └── ReplayPositionTest.java │ ├── databases │ ├── DatabaseManagerCacheTest.java │ └── OnDiskDatabaseManagerTest.java │ ├── metrics │ └── ThreadPoolMetricsTest.java │ ├── operations │ └── ChunkedRecordStreamTest.java │ ├── parser │ └── QueryParserTest.java │ ├── series │ ├── DefaultTimeSeriesPartitionManagerTest.java │ ├── FileMetaDataTest.java │ ├── MapKeyValueIteratorTest.java │ ├── MemTimeSeriesTest.java │ ├── MergingKeyValueIteratorTest.java │ ├── OnDiskTimeSeriesManagerTest.java │ ├── SlabAllocatorTest.java │ ├── TimeSeriesCacheTest.java │ ├── TimeSeriesFileTest.java │ ├── TimeSeriesPartitionManagerCachesTest.java │ └── TimeSeriesPartitionTest.java │ └── util │ └── concurrent │ └── CountDownFutureTest.java └── resources └── horizondb-config.properties /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .classpath 3 | .project 4 | .settings/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HorizonDB 2 | 3 | HorizonDB is a time series database that has been designed specially to store Market data. 4 | 5 | Most of the tick databases today are in memory column oriented database(e.g. KDB). 6 | HorizonDB takes another approach. In HorizonDB, time series are in fact a stream of records where records 7 | can be of different types. 8 | 9 | The advantage of this approach is that disk reads are extremely fast as they involve only a minimum of disk seeks. 10 | So, if you want to load all quotes and trades up to depth 5 for one day of the STX50 for example, it will be extremely 11 | fast as it will involve only one disk seek. 12 | 13 | The disadvantage of this approach is that if your time series contains quotes and trades up to depth 5 and that 14 | you are only interested by the best bid and best ask price, it will be slower than it could be as you will have to read 15 | more data from the disk than what you actually need. Nevertheless, even in this case, the speed should still be reasonable. 16 | If not, you should consider creating another time series with the reduced set of data that you need. As HorizonDB uses 17 | heavily compression the impact on disk usage should be small. 18 | 19 | 20 | ## Project Maturity 21 | 22 | HorizonDB is still in a development phase and has not being officially released. 23 | 24 | ## Requirements 25 | 26 | Oracle JDK >= 1.7 (other JDKs have not been tested) 27 | 28 | ## Inspiration 29 | 30 | HorizonDB has been designed by trying to learn from other existing databases. 31 | 32 | * Cassandra (BigTable): commit log, memtables, slab allocator 33 | * CouchDB/CouchBase: append only B+Tree 34 | * Membase: binary protocol headers 35 | * Mysql: MyISAM compression 36 | 37 | ## License 38 | 39 | Copyright 2013-2014 Benjamin LERER 40 | 41 | HorizonDB is licensed under the [Apache Public License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 4.0.0 20 | io.horizondb 21 | horizondb 22 | 1.0-SNAPSHOT 23 | horizondb 24 | http://maven.apache.org 25 | 26 | 1.7 27 | 1.7 28 | UTF-8 29 | 30 | 31 | 32 | 33 | junit 34 | junit 35 | 4.11 36 | test 37 | 38 | 39 | org.easymock 40 | easymock 41 | 3.0 42 | test 43 | 44 | 45 | io.horizondb 46 | horizondb-test 47 | 1.0-SNAPSHOT 48 | test 49 | 50 | 51 | io.horizondb 52 | horizondb-model 53 | 1.0-SNAPSHOT 54 | 55 | 56 | 57 | 58 | com.codahale.metrics 59 | metrics-core 60 | 3.0.1 61 | 62 | 63 | 64 | org.antlr 65 | antlr4-runtime 66 | 4.2.1 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.antlr 74 | antlr4-maven-plugin 75 | 4.2.2 76 | 77 | 78 | antlr 79 | 80 | antlr4 81 | 82 | 83 | 84 | 85 | 86 | maven-assembly-plugin 87 | 2.4 88 | 89 | src/main/assembly/dep.xml 90 | 91 | 92 | 93 | make-assembly 94 | package 95 | 96 | single 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/assembly/dep.xml: -------------------------------------------------------------------------------- 1 | 4 | bin 5 | 6 | tar.gz 7 | tar.bz2 8 | zip 9 | 10 | 11 | 12 | 13 | README* 14 | LICENSE* 15 | NOTICE* 16 | 17 | 18 | 19 | target 20 | /lib 21 | 22 | *.jar 23 | 24 | 25 | 26 | src/main/scripts/ 27 | /bin 28 | 29 | *.bat 30 | 31 | 32 | 33 | src/main/config/ 34 | /conf 35 | 36 | *.properties 37 | 38 | 39 | 40 | 41 | 42 | /lib 43 | runtime 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/config/horizondb-config.properties: -------------------------------------------------------------------------------- 1 | # the port on which listen the server is listening. 2 | port = 8553 3 | 4 | # the data directory 5 | dataDirectory = /var/lib/horizondb/data; 6 | 7 | # the commit log directory 8 | commitLogDirectory = /var/lib/horizondb/commitlog; -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/Component.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import io.horizondb.db.metrics.Monitorable; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * Describes the lifecycle of a database component. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public interface Component extends Monitorable { 29 | 30 | /** 31 | * Start this database component. 32 | * 33 | * @throws IOException if an IO problem occurs during startup. 34 | * @throws InterruptedException if the thread has been interrupted. 35 | */ 36 | void start() throws IOException, InterruptedException; 37 | 38 | /** 39 | * Shutdown this database component. 40 | * 41 | * @throws InterruptedException if the thread has been interrupted. 42 | */ 43 | void shutdown() throws InterruptedException; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/ConfigurationLoader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | 21 | /** 22 | * Configuration loader. 23 | * 24 | * @author Benjamin 25 | * 26 | */ 27 | public interface ConfigurationLoader { 28 | 29 | /** 30 | * Loads the database configuration from the specified input stream. 31 | * 32 | * @param input the input stream containing the configuration information. 33 | * @return the database configuration 34 | * @throws IOException if an I/O problem occurs while reading the input 35 | * @throws HorizonDBException if the configuration is invalid 36 | */ 37 | Configuration loadConfigurationFrom(InputStream input) throws IOException, HorizonDBException; 38 | 39 | /** 40 | * Loads the database configuration from the specified file within the classpath. 41 | * 42 | * @param filename the name of the configuration file. 43 | * @return the database configuration 44 | * @throws IOException if an I/O problem occurs while reading the input 45 | * @throws HorizonDBException if the configuration is invalid 46 | */ 47 | Configuration loadConfigurationFromClasspath(String filename) throws IOException, HorizonDBException; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/DatabaseEngine.java: -------------------------------------------------------------------------------- 1 | package io.horizondb.db; 2 | /** 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | import io.horizondb.db.databases.DatabaseManager; 18 | import io.horizondb.io.ReadableBuffer; 19 | import io.horizondb.model.protocol.Msg; 20 | 21 | /** 22 | * The storage engine used to persist an retrieve data. 23 | * 24 | */ 25 | public interface DatabaseEngine extends Component { 26 | 27 | /** 28 | * Returns the database manager. 29 | * @return the database manager. 30 | */ 31 | DatabaseManager getDatabaseManager(); 32 | 33 | /** 34 | * Executes the operation requested by the specified message 35 | * 36 | * @param msg the message 37 | * @param buffer the message in its binary form 38 | * @return the message response 39 | */ 40 | Object execute(Msg msg, ReadableBuffer buffer); 41 | } -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/HorizonDBException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | 19 | /** 20 | * Base exception for all the exceptions throw by the database. 21 | * 22 | * @author Benjamin 23 | * 24 | */ 25 | public class HorizonDBException extends Exception { 26 | 27 | /** 28 | * The serial UID 29 | */ 30 | private static final long serialVersionUID = 8640114647378229643L; 31 | 32 | /** 33 | * The error code. 34 | */ 35 | private final int code; 36 | 37 | /** 38 | * Creates a new HorizonDBException with the specified message. 39 | * 40 | * @param code the error code 41 | * @param message the detail message 42 | */ 43 | public HorizonDBException(int code, String message) { 44 | super(message); 45 | this.code = code; 46 | } 47 | 48 | /** 49 | * Creates a new HorizonDBException with the specified message an the specified root cause. 50 | * 51 | * @param code the error code 52 | * @param message the detail message 53 | * @param cause the root cause. 54 | */ 55 | public HorizonDBException(int code, String message, Throwable cause) { 56 | super(message, cause); 57 | this.code = code; 58 | } 59 | 60 | /** 61 | * Returns the error code. 62 | * 63 | * @return the error code. 64 | */ 65 | public int getCode() { 66 | return this.code; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/HorizonDBFiles.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db; 15 | 16 | import io.horizondb.model.schema.DatabaseDefinition; 17 | import io.horizondb.model.schema.TimeSeriesDefinition; 18 | 19 | import java.nio.file.Path; 20 | 21 | /** 22 | * Utility methods related the HorizonDB files. 23 | */ 24 | public final class HorizonDBFiles { 25 | 26 | /** 27 | * The name of the databases file. 28 | */ 29 | private static final String DATABASES_FILENAME = "databases.b3"; 30 | 31 | /** 32 | * The name of the time series file. 33 | */ 34 | private static final String TIMESERIES_FILENAME = "timeseries.b3"; 35 | 36 | /** 37 | * Returns the databases file path. 38 | * 39 | * @param configuration the HorizonDB configuration 40 | * @return the databases file path 41 | */ 42 | public static Path getDatabasesFile(Configuration configuration) { 43 | 44 | return getSystemDirectory(configuration).resolve(DATABASES_FILENAME); 45 | } 46 | 47 | /** 48 | * Returns the timeseries file path. 49 | * 50 | * @param configuration the HorizonDB configuration 51 | * @return the timeseries file path 52 | */ 53 | public static Path getTimeSeriesFile(Configuration configuration) { 54 | 55 | return getSystemDirectory(configuration).resolve(TIMESERIES_FILENAME); 56 | } 57 | 58 | /** 59 | * Returns the system directory, creating it if it does not exists. 60 | * 61 | * @param configuration the HorizonDB configuration 62 | * @return the system directory 63 | */ 64 | public static Path getSystemDirectory(Configuration configuration) { 65 | 66 | Path dataDirectory = configuration.getDataDirectory(); 67 | return dataDirectory.resolve("system"); 68 | } 69 | 70 | /** 71 | * Returns the directory where the time series for the specified database must be stored. 72 | * 73 | * @param configuration the HorizonDB configuration 74 | * @param definition the database definition 75 | * @return the directory where the time series for the specified database must be stored. 76 | */ 77 | public static Path getDatabaseDirectory(Configuration configuration, DatabaseDefinition definition) { 78 | 79 | Path dataDirectory = configuration.getDataDirectory(); 80 | return dataDirectory.resolve(definition.getName() + "-" + definition.getTimestamp()); 81 | } 82 | 83 | /** 84 | * Returns the directory where the time series partitions for the specified time series must be stored. 85 | * 86 | * @param configuration the HorizonDB configuration 87 | * @param databaseDefinition the database definition 88 | * @param timeSeriesDefinition the time series definition 89 | * @return the directory where the time series partition for the specified time series must be stored. 90 | */ 91 | public static Path getTimeSeriesDirectory(Configuration configuration, 92 | DatabaseDefinition databaseDefinition, 93 | TimeSeriesDefinition timeSeriesDefinition) { 94 | 95 | Path databaseDirectory = getDatabaseDirectory(configuration, databaseDefinition); 96 | return databaseDirectory.resolve(timeSeriesDefinition.getName() + "-" + timeSeriesDefinition.getTimestamp()); 97 | } 98 | 99 | /** 100 | * Must not be instantiated 101 | */ 102 | private HorizonDBFiles() { 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/HorizonServerHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import io.horizondb.io.Buffer; 19 | import io.horizondb.io.buffers.Buffers; 20 | import io.horizondb.model.ErrorCodes; 21 | import io.horizondb.model.protocol.Msg; 22 | import io.horizondb.model.protocol.Msgs; 23 | import io.netty.buffer.ByteBuf; 24 | import io.netty.channel.ChannelHandlerContext; 25 | import io.netty.channel.ChannelInboundHandlerAdapter; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | import static org.apache.commons.lang.Validate.notNull; 31 | 32 | class HorizonServerHandler extends ChannelInboundHandlerAdapter { 33 | 34 | /** 35 | * The class logger. 36 | */ 37 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 38 | 39 | /** 40 | * The database engine. 41 | */ 42 | private final DatabaseEngine engine; 43 | 44 | public HorizonServerHandler(DatabaseEngine engine) { 45 | 46 | notNull(engine, "the engine parameter must not be null."); 47 | 48 | this.engine = engine; 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | @Override 55 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 56 | 57 | Buffer buffer = Buffers.wrap((ByteBuf) msg); 58 | 59 | Msg request = Msg.parseFrom(buffer); 60 | 61 | Object response = this.engine.execute(request, buffer); 62 | 63 | if (response instanceof Iterable) { 64 | 65 | for (Object chunk : (Iterable) response) { 66 | ctx.channel().writeAndFlush(chunk); 67 | } 68 | 69 | } else { 70 | ctx.channel().writeAndFlush(response); 71 | } 72 | } 73 | 74 | /** 75 | * {@inheritDoc} 76 | */ 77 | @Override 78 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 79 | 80 | this.logger.error("Unexpected exception from downstream.", cause); 81 | 82 | if (ctx.channel().isActive()) { 83 | 84 | ctx.channel().writeAndFlush(Msgs.newErrorMsg(ErrorCodes.INTERNAL_ERROR, cause.getMessage())); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/HqlConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db; 15 | 16 | import io.horizondb.db.databases.DatabaseManager; 17 | import io.horizondb.db.parser.QueryParser; 18 | import io.horizondb.io.ReadableBuffer; 19 | import io.horizondb.model.ErrorCodes; 20 | import io.horizondb.model.protocol.HqlQueryPayload; 21 | import io.horizondb.model.protocol.Msg; 22 | import io.horizondb.model.protocol.Msgs; 23 | import io.horizondb.model.protocol.OpCode; 24 | 25 | import java.io.IOException; 26 | 27 | import com.codahale.metrics.MetricRegistry; 28 | 29 | /** 30 | * Decorator that convert HQL query messages in low-level messages. 31 | */ 32 | public class HqlConverter extends AbstractComponent implements DatabaseEngine { 33 | 34 | /** 35 | * The database configuration. 36 | */ 37 | private final Configuration configuration; 38 | 39 | /** 40 | * The database engine. 41 | */ 42 | private final DatabaseEngine databaseEngine; 43 | 44 | public HqlConverter(Configuration configuration, DatabaseEngine databaseEngine) { 45 | 46 | this.configuration = configuration; 47 | this.databaseEngine = databaseEngine; 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | @Override 54 | public void register(MetricRegistry registry) { 55 | 56 | this.databaseEngine.register(registry); 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | @Override 63 | public void unregister(MetricRegistry registry) { 64 | 65 | this.databaseEngine.unregister(registry); 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | */ 71 | @Override 72 | protected void doStart() throws IOException, InterruptedException { 73 | 74 | this.databaseEngine.start(); 75 | } 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | @Override 81 | protected void doShutdown() throws InterruptedException { 82 | 83 | this.databaseEngine.shutdown(); 84 | } 85 | 86 | /** 87 | * {@inheritDoc} 88 | */ 89 | @Override 90 | public DatabaseManager getDatabaseManager() { 91 | return this.databaseEngine.getDatabaseManager(); 92 | } 93 | 94 | /** 95 | * {@inheritDoc} 96 | */ 97 | @Override 98 | public Object execute(Msg request, ReadableBuffer buffer) { 99 | 100 | try { 101 | 102 | OpCode opCode = request.getOpCode(); 103 | 104 | this.logger.debug("Message received with operation code: " + opCode); 105 | 106 | if (opCode.isHql()) { 107 | 108 | @SuppressWarnings("unchecked") 109 | Msg msg = QueryParser.parse(this.configuration, 110 | this.databaseEngine.getDatabaseManager(), 111 | (Msg) request); 112 | 113 | return this.databaseEngine.execute(msg, null); 114 | } 115 | 116 | return this.databaseEngine.execute(request, buffer); 117 | 118 | } catch (HorizonDBException e) { 119 | 120 | return Msgs.newErrorMsg(e.getCode(), e.getMessage()); 121 | 122 | } catch (Exception e) { 123 | 124 | this.logger.error("", e); 125 | 126 | return Msgs.newErrorMsg(ErrorCodes.INTERNAL_ERROR, e.getMessage()); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/MsgToByteEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import java.nio.ByteOrder; 19 | 20 | import io.horizondb.io.buffers.Buffers; 21 | import io.horizondb.model.protocol.Msg; 22 | import io.netty.buffer.ByteBuf; 23 | import io.netty.channel.ChannelHandlerContext; 24 | import io.netty.handler.codec.MessageToByteEncoder; 25 | 26 | /** 27 | * Encoder for Msg. 28 | * 29 | * @author Benjamin 30 | * 31 | */ 32 | final class MsgToByteEncoder extends MessageToByteEncoder> { 33 | 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | @Override 38 | protected void encode(ChannelHandlerContext ctx, Msg msg, ByteBuf out) throws Exception { 39 | 40 | out.writerIndex(Buffers.wrap(out.capacity(msg.computeSerializedSize())) 41 | .order(ByteOrder.LITTLE_ENDIAN) 42 | .writeObject(msg) 43 | .writerIndex()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/Operation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import java.io.IOException; 19 | 20 | import io.horizondb.model.protocol.Msg; 21 | 22 | /** 23 | * Performs the operation requested by the specified message. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public interface Operation { 29 | 30 | /** 31 | * Performs the operation requested by the specified request. 32 | * 33 | * @param context the operation context. 34 | * @param request the request. 35 | * @return the response. 36 | * @throws HorizonDBException if an error occur while performing the operation 37 | * @throws IOException if an I/O problem occurs while performing the operation 38 | */ 39 | Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/Query.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db; 15 | 16 | 17 | import java.io.IOException; 18 | 19 | /** 20 | * A user query. 21 | * 22 | * @author Benjamin 23 | * 24 | */ 25 | public interface Query { 26 | 27 | /** 28 | * Executes this query. 29 | * 30 | * @param context the query context. 31 | * @return the response. 32 | * @throws HorizonDBException if an error occur while performing the operation 33 | * @throws IOException if an I/O problem occurs while performing the operation 34 | */ 35 | Object execute(QueryContext context) throws IOException, HorizonDBException; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/QueryContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db; 15 | 16 | import io.horizondb.db.databases.DatabaseManager; 17 | import io.horizondb.model.protocol.MsgHeader; 18 | 19 | /** 20 | * The context in which a query must be executed. 21 | * 22 | * @author Benjamin 23 | * 24 | */ 25 | public final class QueryContext { 26 | 27 | /** 28 | * The operation context. 29 | */ 30 | private final OperationContext operationContext; 31 | 32 | /** 33 | * The request message header. 34 | */ 35 | private final MsgHeader requestHeader; 36 | 37 | /** 38 | * The name of the database on which the query must be performed. 39 | */ 40 | private final String databaseName; 41 | 42 | /** 43 | * Creates a new QueryContext that will be executed within the specified 44 | * operation context. 45 | * 46 | * @param operationContext the operation context 47 | * @param requestHeader the request message header 48 | * @param databaseName the database name 49 | */ 50 | public QueryContext(OperationContext operationContext, 51 | MsgHeader requestHeader, 52 | String databaseName) { 53 | 54 | this.operationContext = operationContext; 55 | this.requestHeader = requestHeader; 56 | this.databaseName = databaseName; 57 | } 58 | 59 | /** 60 | * Returns the database manager. 61 | * 62 | * @return the database manager. 63 | */ 64 | public DatabaseManager getDatabaseManager() { 65 | return this.operationContext.getDatabaseManager(); 66 | } 67 | 68 | /** 69 | * Returns true if the query is a replay from the commit log. 70 | * 71 | * @return true if the query is a replay from the commit log. 72 | */ 73 | public boolean isReplay() { 74 | return this.operationContext.isReplay(); 75 | } 76 | 77 | /** 78 | * Returns the header of the request message. 79 | * 80 | * @return the header of the request message. 81 | */ 82 | public MsgHeader getRequestHeader() { 83 | return this.requestHeader; 84 | } 85 | 86 | /** 87 | * Returns the name of the database on which the query must be performed. 88 | * 89 | * @return the name of the database on which the query must be performed. 90 | */ 91 | public String getDatabaseName() { 92 | return this.databaseName; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/StorageEngine.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import io.horizondb.db.commitlog.ReplayPosition; 19 | import io.horizondb.db.databases.DatabaseManager; 20 | import io.horizondb.io.ReadableBuffer; 21 | import io.horizondb.model.protocol.Msg; 22 | 23 | import java.io.IOException; 24 | 25 | import com.google.common.util.concurrent.ListenableFuture; 26 | 27 | /** 28 | * The storage engine used to persist an retrieve data. 29 | * 30 | */ 31 | public interface StorageEngine extends Component { 32 | 33 | /** 34 | * Returns the database manager 35 | * @return the database manager 36 | */ 37 | DatabaseManager getDatabaseManager(); 38 | 39 | /** 40 | * Executes the operation requested by the specified message 41 | * 42 | * @param request the message 43 | * @param future the commit log future or null if the message was not a mutation. 44 | * @return the message response 45 | * @throws IOException if an I/O problem occurs 46 | * @throws HorizonDBException if a problem occurs while processing the request 47 | */ 48 | Object execute(Msg request, ListenableFuture future) throws IOException, HorizonDBException; 49 | 50 | /** 51 | * Flush to the disk all the data that have not been persisted yet and that come from the 52 | * segment with the specified ID. 53 | * 54 | * @param id the segment id 55 | * @return a ListenableFuture that will return when all the data have been flushed to disk. 56 | * @throws InterruptedException if the thread is interrupted 57 | */ 58 | ListenableFuture forceFlush(long id) throws InterruptedException; 59 | 60 | /** 61 | * Replays the specified message. 62 | * 63 | * @param replayPosition the replay position associated with the message 64 | * @param buffer the message in its binary form 65 | * @throws IOException if an I/O problem occurs during the replay 66 | */ 67 | void replay(ReplayPosition replayPosition, ReadableBuffer buffer) throws IOException; 68 | } -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/AbstractNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | /** 19 | * Base class for the Node classes. 20 | * 21 | * @author Benjamin 22 | * 23 | */ 24 | abstract class AbstractNode, V> implements Node { 25 | 26 | /** 27 | * The B+Tree to which this node belongs. 28 | */ 29 | private final BTree btree; 30 | 31 | /** 32 | * Creates a new AbstractNode. 33 | * 34 | * @param btree the B+Tree to which this node belongs. 35 | */ 36 | public AbstractNode(BTree btree) { 37 | this.btree = btree; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | @Override 44 | public final boolean hasMoreThanMinimumNumberOfElement() { 45 | 46 | return getNumberOfElements() > getMinimumNumberOfElements(); 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | @Override 53 | public final boolean hasLessThanMinimumNumberOfElement() { 54 | 55 | return getNumberOfElements() < getMinimumNumberOfElements(); 56 | } 57 | 58 | /** 59 | * Returns the B+Tree branching factor. 60 | * 61 | * @return the B+Tree branching factor. 62 | */ 63 | protected int getBranchingFactor() { 64 | 65 | return this.btree.getBranchingFactor(); 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | */ 71 | @Override 72 | public BTree getBTree() { 73 | 74 | return this.btree; 75 | } 76 | 77 | /** 78 | * Returns the number of elements from this node. 79 | * 80 | * @return the number of elements from this node. 81 | */ 82 | protected abstract int getNumberOfElements(); 83 | 84 | /** 85 | * Returns the minimum number of elements that this node must contains. 86 | * 87 | * @return the minimum number of elements that this node must contains. 88 | */ 89 | protected abstract int getMinimumNumberOfElements(); 90 | 91 | /** 92 | * {@inheritDoc} 93 | */ 94 | public int getSubTreeSize() { 95 | return 0; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/BlockPrefixes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | /** 19 | * The prefixes for the different types of blocks. 20 | * 21 | * @author Benjamin 22 | */ 23 | final class BlockPrefixes { 24 | 25 | /** 26 | * The prefix for data blocks. 27 | */ 28 | public static final byte DATA_BLOCK_PREFIX = 0; 29 | 30 | /** 31 | * The prefix for header blocks. 32 | */ 33 | public static final byte HEADER_BLOCK_PREFIX = 1; 34 | 35 | /** 36 | * Must not be instantiated. 37 | */ 38 | private BlockPrefixes() { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/Constants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import static io.horizondb.io.files.FileUtils.ONE_KB; 19 | 20 | /** 21 | * @author Benjamin 22 | * 23 | */ 24 | final class Constants { 25 | 26 | /** 27 | * Specify that the data within the file are not compressed. 28 | */ 29 | public static int NO_COMPRESSION = 0; 30 | 31 | /** 32 | * The current version of the file format. 33 | */ 34 | public static int CURRENT_VERSION = 1; 35 | 36 | /** 37 | * The size of the blocks within the B+Tree files. 38 | */ 39 | public static final int BLOCK_SIZE = 4 * ONE_KB; 40 | 41 | /** 42 | * Must not be instantiated. 43 | */ 44 | private Constants() { 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/DataPointer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import org.apache.commons.lang.builder.ToStringBuilder; 19 | import org.apache.commons.lang.builder.ToStringStyle; 20 | 21 | /** 22 | * Pointer towards some data serialized on disk. 23 | * 24 | * @author Benjamin 25 | * 26 | */ 27 | class DataPointer, V> { 28 | 29 | /** 30 | * The manager that should be used to retrieve the data. 31 | */ 32 | private final OnDiskNodeManager manager; 33 | 34 | /** 35 | * The position of the data within the file. 36 | */ 37 | private final long position; 38 | 39 | /** 40 | * The size of the sub-tree on disk. 41 | */ 42 | private final int subTreeSize; 43 | 44 | /** 45 | * Creates a new pointer towards some data stored on the disk. 46 | * 47 | * @param manager The manager that should be used to retrieve the data.. 48 | * @param position The position of the data within the file. 49 | * @param subTreeSize The size in byte of the sub-tree. 50 | */ 51 | public DataPointer(OnDiskNodeManager manager, long position, int subTreeSize) { 52 | 53 | this.manager = manager; 54 | this.position = position; 55 | this.subTreeSize = subTreeSize; 56 | } 57 | 58 | /** 59 | * Returns the manager that should be used to retrieve the data. 60 | * 61 | * @return the manager that should be used to retrieve the data. 62 | */ 63 | public final OnDiskNodeManager getManager() { 64 | return this.manager; 65 | } 66 | 67 | /** 68 | * Returns the position of the data within the file. 69 | * 70 | * @return the position of the data within the file. 71 | */ 72 | public final long getPosition() { 73 | return this.position; 74 | } 75 | 76 | /** 77 | * Returns the size of the sub-tree on disk. 78 | * 79 | * @return the size of the sub-tree on disk. 80 | */ 81 | public int getSubTreeSize() { 82 | return this.subTreeSize; 83 | } 84 | 85 | /** 86 | * {@inheritDoc} 87 | */ 88 | @Override 89 | public String toString() { 90 | 91 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("manager", this.manager) 92 | .append("position", this.position) 93 | .append("subTreeSize", this.subTreeSize) 94 | .toString(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/DefaultValueWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | /** 19 | * Default implementation of the ValueWrapper. 20 | * 21 | * @author Benjamin 22 | * 23 | */ 24 | final class DefaultValueWrapper implements ValueWrapper { 25 | 26 | /** 27 | * The value. 28 | */ 29 | private final V value; 30 | 31 | /** 32 | * @param manager 33 | */ 34 | public DefaultValueWrapper(V value) { 35 | this.value = value; 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | @Override 42 | public V getValue() { 43 | 44 | return this.value; 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | public String toString() { 52 | return this.value.toString(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/InMemoryNodeManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.IOException; 19 | import java.util.concurrent.atomic.AtomicReference; 20 | 21 | import com.codahale.metrics.MetricRegistry; 22 | 23 | import static org.apache.commons.lang.Validate.notNull; 24 | 25 | /** 26 | * NodeManager that keeps all the Nodes in memory. 27 | * 28 | *

29 | * This NodeManager provides no durability and should only be used for 30 | * testing purpose. 31 | *

32 | * 33 | * @param the key type. 34 | * @param the value type. 35 | */ 36 | public final class InMemoryNodeManager, V> implements NodeManager { 37 | 38 | /** 39 | * This manager name. 40 | */ 41 | private final String name; 42 | 43 | /** 44 | * The root node. 45 | */ 46 | private final AtomicReference> root = new AtomicReference<>(); 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | @Override 52 | public void register(MetricRegistry registry) { 53 | 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public void unregister(MetricRegistry registry) { 61 | 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public String getName() { 69 | return this.name; 70 | } 71 | 72 | /** 73 | * Creates a new InMemoryNodeManager with the spcified name. 74 | * @param name the node manager name 75 | */ 76 | public InMemoryNodeManager(String name) 77 | { 78 | notNull(name, "the name parameter must not be null."); 79 | this.name = name; 80 | } 81 | 82 | /** 83 | * {@inheritDoc} 84 | */ 85 | @Override 86 | public Node getRoot(BTree btree) { 87 | 88 | Node node = this.root.get(); 89 | 90 | if (node == null) { 91 | 92 | this.root.compareAndSet(null, new LeafNode<>(btree)); 93 | node = this.root.get(); 94 | } 95 | 96 | return node; 97 | } 98 | 99 | /** 100 | * {@inheritDoc} 101 | */ 102 | @Override 103 | public void setRoot(Node root) { 104 | 105 | this.root.set(root); 106 | } 107 | 108 | /** 109 | * {@inheritDoc} 110 | */ 111 | @Override 112 | @SafeVarargs 113 | public final Node[] wrapNodes(Node... nodes) throws IOException { 114 | 115 | return nodes; 116 | } 117 | 118 | /** 119 | * {@inheritDoc} 120 | */ 121 | @Override 122 | public Node wrapNode(Node node) throws IOException { 123 | 124 | return node; 125 | } 126 | 127 | /** 128 | * {@inheritDoc} 129 | */ 130 | @Override 131 | public Node unwrapNode(Node node) throws IOException { 132 | 133 | return node; 134 | } 135 | 136 | /** 137 | * {@inheritDoc} 138 | */ 139 | @Override 140 | public ValueWrapper wrapValue(V value) { 141 | 142 | return new DefaultValueWrapper(value); 143 | } 144 | 145 | /** 146 | * {@inheritDoc} 147 | */ 148 | @Override 149 | public void close() { 150 | 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/KeyValueIterator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.btree; 15 | 16 | import java.io.IOException; 17 | 18 | /** 19 | * @author Benjamin 20 | * 21 | */ 22 | public interface KeyValueIterator, V> { 23 | 24 | /** 25 | * Moves the cursor to the next entry. 26 | * 27 | * @return true if the cursor could be moved successfully to the next entry, false 28 | * otherwise. 29 | * @throws IOException if an I/O problem occurs while retrieving the next record. 30 | */ 31 | boolean next() throws IOException; 32 | 33 | /** 34 | * Returns the key of the current entry. 35 | * 36 | * @return the key of the current entry. 37 | */ 38 | K getKey(); 39 | 40 | /** 41 | * Returns the value of the current entry. 42 | * 43 | * @return the value of the current entry. 44 | * @throws IOException if an I/O problem occurs 45 | */ 46 | V getValue() throws IOException; 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import io.horizondb.db.metrics.Monitorable; 19 | 20 | import java.io.Closeable; 21 | import java.io.IOException; 22 | 23 | /** 24 | * Manager in charge of saving and loading BTree nodes. 25 | * 26 | * @param the Key type. 27 | * @param the Value type. 28 | */ 29 | public interface NodeManager, V> extends Closeable, Monitorable { 30 | 31 | /** 32 | * Returns the root node of the specified BTree. 33 | * 34 | * @param btree the BTree. 35 | * @return the root node. 36 | * @throws IOException if an I/O problem occurs. 37 | */ 38 | Node getRoot(BTree btree) throws IOException; 39 | 40 | /** 41 | * Sets the new root node. 42 | * 43 | * @param root the new root node. 44 | * @throws IOException if an I/O problem occurs. 45 | */ 46 | void setRoot(Node root) throws IOException; 47 | 48 | /** 49 | * Allows this manager to take control of the storage of specified node. 50 | * 51 | * @param node the node. 52 | * @return the decorated node. 53 | * @throws IOException if an I/O problem occurs. 54 | */ 55 | @SuppressWarnings("unchecked") 56 | Node[] wrapNodes(Node... nodes) throws IOException; 57 | 58 | /** 59 | * Allows this manager to take control of the storage of specified node. 60 | * 61 | * @param node the node. 62 | * @return the decorated node. 63 | * @throws IOException if an I/O problem occurs. 64 | */ 65 | Node wrapNode(Node node) throws IOException; 66 | 67 | /** 68 | * Allows the user of the node to retrieve the original node. 69 | * 70 | * @param node the decorated node. 71 | * @return the node. 72 | * @throws IOException if an I/O problem occurs. 73 | */ 74 | Node unwrapNode(Node node) throws IOException; 75 | 76 | /** 77 | * Allows this manager to take control of the storage of specified value. 78 | * 79 | * @param value the value. 80 | * @return the decorated value. 81 | * @throws IOException if an I/O problem occurs. 82 | */ 83 | ValueWrapper wrapValue(V value) throws IOException; 84 | 85 | /** 86 | * {@inheritDoc} 87 | */ 88 | @Override 89 | void close(); 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeReader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.Closeable; 19 | import java.io.IOException; 20 | 21 | /** 22 | * The reader used to read the B+Tree data from the disk. 23 | * 24 | * @author Benjamin 25 | * 26 | */ 27 | public interface NodeReader, V> extends Closeable { 28 | 29 | /** 30 | * Reads the file header and returns the corresponding root node. 31 | * 32 | * @param btree the B+Tree to which belongs the root node. 33 | * @throws IOException if an I/O problem occurs while reading the data. 34 | */ 35 | Node readRoot(BTree btree) throws IOException; 36 | 37 | /** 38 | * Reads the node data located at the specified position. 39 | * 40 | * @param btree the B+Tree to which belongs the node. 41 | * @param position the position of the node data within the file. 42 | * @return the node 43 | * @throws IOException if an I/O problem occurs while reading the data. 44 | */ 45 | Node readNode(BTree btree, long position) throws IOException; 46 | 47 | /** 48 | * Returns the data located at the specified position. 49 | * 50 | * @param position the position of the data within the file. 51 | * @return the data located at the specified position. 52 | * @throws IOException if an I/O problem occurs while reading the data. 53 | */ 54 | V readData(long position) throws IOException; 55 | 56 | /** 57 | * Close this node reader without throwing an exception. 58 | */ 59 | void closeQuietly(); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeReaderFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import io.horizondb.io.files.SeekableFileDataInput; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * Factory for NodeReader instances. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public interface NodeReaderFactory, V> { 29 | 30 | /** 31 | * Creates a new reader instance that use the specified input to read from the file. 32 | * 33 | * @param input the file input. 34 | * @return a new reader instance that use the specified input to read from the file. 35 | * @throws IOException if an I/O problem occurs. 36 | */ 37 | NodeReader newReader(SeekableFileDataInput input) throws IOException; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeVisitor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * A visitor of B+Tree nodes. 22 | * 23 | * @author Benjamin 24 | * 25 | */ 26 | public interface NodeVisitor, V> { 27 | 28 | /** 29 | * Invoked for a node before children or records of the node are visited. 30 | * 31 | *

32 | * If this method returns {@link NodeVisitResult#CONTINUE CONTINUE}, then children or records of the node. If this 33 | * method returns {@link NodeVisitResult#SKIP_SUBTREE SKIP_SUBTREE} or {@link NodeVisitResult#SKIP_SIBLINGS 34 | * SKIP_SIBLINGS} then children or records of the node will not be visited. 35 | * 36 | * @param key the key to which the node is associated 37 | * @param node the node that will be visited 38 | * @return the visit result 39 | * @throws IOException if an I/O problem occurs. 40 | */ 41 | NodeVisitResult preVisitNode(K key, Node node) throws IOException; 42 | 43 | /** 44 | * Invoked for a node after children or records of the node are visited, and all of their descendants, have been 45 | * visited. This method is also invoked when iteration of the node completes prematurely (by a {@link #visitRecord} 46 | * method returning {@link NodeVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS}. 47 | * 48 | * @param key the key to which the node is associated 49 | * @param node the node that will be visited 50 | * @return the visit result 51 | * @throws IOException if an I/O problem occurs. 52 | */ 53 | NodeVisitResult postVisitNode(K key, Node node) throws IOException; 54 | 55 | /** 56 | * Invoked for a record in a leaf node. 57 | * 58 | * @param key the record key. 59 | * @param wrapper the value wrapper. 60 | * @return the visit result 61 | * @throws IOException if an I/O problem occurs. 62 | */ 63 | NodeVisitResult visitRecord(K key, ValueWrapper wrapper) throws IOException; 64 | 65 | /** 66 | * The result type of a {@link NodeVisitor}. 67 | */ 68 | public static enum NodeVisitResult { 69 | 70 | /** 71 | * Continue. When returned from a {@link NodeVisitor#preVisitNode(Comparable, Node)} method then the children or 72 | * records of the node should also be visited. 73 | */ 74 | CONTINUE, 75 | 76 | /** 77 | * Terminate. 78 | */ 79 | TERMINATE, 80 | 81 | /** 82 | * Continue without visiting the children or records of the node. This result is only meaningful when returned 83 | * from the {@link {@link NodeVisitor#preVisitNode(Comparable, Node)} method; otherwise this result type is 84 | * the same as returning {@link #CONTINUE}. 85 | */ 86 | SKIP_SUBTREE, 87 | 88 | /** 89 | * Continue without visiting the siblings of this node or record. If returned from the 90 | * {@link NodeVisitor#preVisitNode(Comparable, Node)} method then children or records of the node are also 91 | * skipped and the {@link NodeVisitor#postVisitNode(Comparable, Node)} method is not invoked. 92 | */ 93 | SKIP_SIBLINGS; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeWriter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.Closeable; 19 | import java.io.Flushable; 20 | import java.io.IOException; 21 | 22 | /** 23 | * The writer used to write the B+Tree data to the disk. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public interface NodeWriter, V> extends Closeable, Flushable { 29 | 30 | /** 31 | * Writes the specified node to the underlying file. 32 | * 33 | * @param node the node to write. 34 | * @returns the size on disk of the sub-tree. 35 | * @throws IOException if an I/O problem occurs while writing the node. 36 | */ 37 | int writeNode(Node node) throws IOException; 38 | 39 | /** 40 | * Writes the specified data to the underlying file. 41 | * 42 | * @param value the data value. 43 | * @returns the size on disk of the value. 44 | * @throws IOException if an I/O problem occurs while writing the data. 45 | */ 46 | int writeData(V value) throws IOException; 47 | 48 | /** 49 | * Writes the header corresponding to the specified root node. 50 | * 51 | * @param node the root node. 52 | * @throws IOException if an I/O problem occurs while writing the data. 53 | */ 54 | void writeRoot(Node node) throws IOException; 55 | 56 | /** 57 | * Returns the current position within the file. 58 | * 59 | * @return the current position within the underlying file. 60 | * @throws IOException if an I/O problem occurs while writing the data. 61 | */ 62 | long getPosition() throws IOException; 63 | 64 | /** 65 | * Close this node writer without throwing an exception. 66 | */ 67 | void closeQuietly(); 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/NodeWriterFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import io.horizondb.io.files.FileDataOutput; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * Factory for NodeWriter instances. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public interface NodeWriterFactory, V> { 29 | 30 | /** 31 | * Creates a new writer instance that use the specified output to write to the file. 32 | * 33 | * @param output the file output. 34 | * @return a new writer instance that use the specified output to write to the file. 35 | * @throws IOException if a problem occurs while creating a writer instance. 36 | */ 37 | NodeWriter newWriter(FileDataOutput output) throws IOException; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/SimpleNodeVisitor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * NodeVisitor that simply visit the nodes and records without doing anything. 22 | * 23 | * @author Benjamin 24 | * 25 | */ 26 | public class SimpleNodeVisitor, V> implements NodeVisitor { 27 | 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | @Override 32 | public NodeVisitResult preVisitNode(K key, Node node) throws IOException { 33 | return NodeVisitResult.CONTINUE; 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | @Override 40 | public NodeVisitResult postVisitNode(K key, Node node) throws IOException { 41 | return NodeVisitResult.CONTINUE; 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | @Override 48 | public NodeVisitResult visitRecord(K key, ValueWrapper pointer) throws IOException { 49 | return NodeVisitResult.CONTINUE; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/ValueProxy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.IOException; 19 | 20 | import org.apache.commons.lang.builder.ToStringBuilder; 21 | import org.apache.commons.lang.builder.ToStringStyle; 22 | 23 | /** 24 | * A proxy toward a some data stored on the disk. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | final class ValueProxy, V> extends DataPointer implements ValueWrapper { 30 | 31 | /** 32 | * Creates a new proxy toward a value stored on disk. 33 | * 34 | * @param manager The manager associated to this pointer. 35 | * @param position The position of the data within the file. 36 | * @param length The length of the data. 37 | */ 38 | public ValueProxy(OnDiskNodeManager manager, long position, int length) { 39 | 40 | super(manager, position, length); 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @Override 47 | public V getValue() throws IOException { 48 | 49 | return getManager().loadValue(this); 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | @Override 56 | public String toString() { 57 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).appendSuper(super.toString()).toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/btree/ValueWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * Wrapper of a specified value. 22 | * 23 | * @author Benjamin 24 | * 25 | * @param the type of the wrapped value. 26 | */ 27 | interface ValueWrapper { 28 | 29 | /** 30 | * Returns the wrapped value. 31 | * 32 | * @return the wrapped value. 33 | * @throws IOException if an I/O problem occurs. 34 | */ 35 | V getValue() throws IOException; 36 | } -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/cache/AbstractMultilevelCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.cache; 17 | 18 | import io.horizondb.db.Configuration; 19 | 20 | import java.util.concurrent.Callable; 21 | import java.util.concurrent.ExecutionException; 22 | import org.apache.commons.lang.builder.ToStringBuilder; 23 | import org.apache.commons.lang.builder.ToStringStyle; 24 | 25 | /** 26 | * Base class for Cache implementation with multilevel. 27 | * 28 | * @author Benjamin 29 | * 30 | */ 31 | public abstract class AbstractMultilevelCache extends AbstractCache { 32 | 33 | /** 34 | * The second level cache. 35 | */ 36 | private final io.horizondb.db.cache.Cache secondLevelCache; 37 | 38 | /** 39 | * Creates a AbstractCache. 40 | * 41 | * @param configuration the database configuration. 42 | * @param secondLevelCache the second level cache. 43 | */ 44 | public AbstractMultilevelCache(Configuration configuration, 45 | io.horizondb.db.cache.Cache secondLevelCache) { 46 | 47 | super(configuration); 48 | this.secondLevelCache = secondLevelCache; 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | @Override 55 | public String toString() { 56 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 57 | .appendSuper(super.toString()) 58 | .append("secondLevelCache", this.secondLevelCache) 59 | .toString(); 60 | } 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | @Override 66 | protected V doGet(final K key, final ValueLoader loader) throws ExecutionException { 67 | 68 | return doGet(key, new Callable() { 69 | 70 | /** 71 | * {@inheritDoc} 72 | */ 73 | @Override 74 | public V call() throws Exception { 75 | 76 | final V value = AbstractMultilevelCache.this.secondLevelCache.get(key, loader); 77 | 78 | AbstractMultilevelCache.this.afterLoad(value); 79 | 80 | return value; 81 | } 82 | }); 83 | } 84 | 85 | /** 86 | * Allows a sub-classes to perform operations on a loaded value before returning it. 87 | * 88 | * @param value the loaded value 89 | */ 90 | protected void afterLoad(V value) { 91 | 92 | } 93 | 94 | /** 95 | * Returns the second level cache. 96 | * @return the second level cache. 97 | */ 98 | protected final io.horizondb.db.cache.Cache getSecondLevelCache() { 99 | return this.secondLevelCache; 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/cache/Cache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.cache; 17 | 18 | import java.io.IOException; 19 | 20 | import io.horizondb.db.Component; 21 | import io.horizondb.db.HorizonDBException; 22 | 23 | /** 24 | * A caching component. 25 | * 26 | * @param K the key type 27 | * @param V the value type 28 | * 29 | * @author Benjamin 30 | */ 31 | public interface Cache extends Component { 32 | 33 | /** 34 | * Puts the specified entry in the cache. 35 | * 36 | * @param key the entry key 37 | * @param value the entry value 38 | */ 39 | void put(K key, V value); 40 | 41 | /** 42 | * Returns the value associated to the specified key. If the key is not present in the cache the value will be 43 | * loaded using the specified ValueLoader. 44 | * 45 | * @param key the value key 46 | * @param loader the loader that will be used to load the value if the key is not present within the cache 47 | * @return the value associated to the specified key 48 | * @throws IOException if an I/O problem occurs 49 | * @throws HorizonDBException if a problem occurs 50 | */ 51 | V get(K key, ValueLoader loader) throws IOException, HorizonDBException; 52 | 53 | /** 54 | * Returns the value associated to the specified key if it is present within the cache. 55 | * 56 | * @param key the value key 57 | * @return the value associated to the specified key 58 | */ 59 | V getIfPresent(K key); 60 | 61 | /** 62 | * Invalidates the entry with the specified key. 63 | * @param key the entry key 64 | */ 65 | void invalidate(K key); 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/cache/CallableAdaptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.cache; 17 | 18 | import java.util.concurrent.Callable; 19 | 20 | /** 21 | * Adaptor that adapts a ValueLoader to the Callable interface. 22 | * 23 | * @author Benjamin 24 | */ 25 | final class CallableAdaptor implements Callable { 26 | 27 | /** 28 | * The adapted ValueLoader. 29 | */ 30 | private final ValueLoader loader; 31 | 32 | /** 33 | * The key for which the value must be loaded. 34 | */ 35 | private final K key; 36 | 37 | /** 38 | * Creates a new CallableAdaptor that adapt the specified loader. 39 | * 40 | * @param key the key for which the value must be loaded 41 | * @param loader the loader to adapt 42 | */ 43 | public CallableAdaptor(K key, ValueLoader loader) { 44 | 45 | this.key = key; 46 | this.loader = loader; 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | @Override 53 | public V call() throws Exception { 54 | return this.loader.loadValue(this.key); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/cache/ValueLoader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.cache; 17 | 18 | import io.horizondb.db.HorizonDBException; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * @author Benjamin 24 | * 25 | */ 26 | public interface ValueLoader { 27 | 28 | /** 29 | * Loads the value associated to the specified key. 30 | * 31 | * @param key the cache key 32 | * @return the value associated to the specified key 33 | * @throws IOException if an I/O problem occurs 34 | * @throws HorizonDBException if another problem occurs 35 | */ 36 | V loadValue(K key) throws IOException, HorizonDBException; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/commitlog/BatchWriteExecutor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.commitlog; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.commitlog.CommitLog.FlushTask; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * A WriteExecutor that flush the data to disk after a specified amount of time. 25 | * 26 | * @author Benjamin 27 | */ 28 | final class BatchWriteExecutor extends AbstractWriteExecutor { 29 | 30 | public BatchWriteExecutor(Configuration configuration, FlushTask flushTask) { 31 | 32 | super(configuration, flushTask); 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | protected WriteThreadPoolExecutor createWriteThreadPoolExecutor(final Configuration configuration, 40 | final String name, 41 | final FlushTask flushTask) { 42 | return new BatchExecutorService(configuration, name, flushTask); 43 | } 44 | 45 | /** 46 | * ScheduledThreadPoolExecutor that flush the data to disk after a specified time. 47 | * 48 | */ 49 | private static final class BatchExecutorService extends WriteThreadPoolExecutor { 50 | 51 | /** 52 | * The database configuration. 53 | */ 54 | private final Configuration configuration; 55 | 56 | /** 57 | * true if a flush has been scheduled, false otherwise. 58 | */ 59 | private volatile boolean hasScheduledFlush; 60 | 61 | public BatchExecutorService(Configuration configuration, String name, FlushTask flushTask) { 62 | super(name, flushTask); 63 | 64 | this.configuration = configuration; 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | @Override 71 | protected void beforeWrite() { 72 | 73 | if (!this.hasScheduledFlush && !isTerminating()) { 74 | 75 | schedule(getFlushTask(), 76 | this.configuration.getCommitLogBatchWindowInMillis(), 77 | TimeUnit.MILLISECONDS); 78 | } 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | */ 84 | @Override 85 | protected void afterFlush() { 86 | this.hasScheduledFlush = false; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/commitlog/IdFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.commitlog; 17 | 18 | import java.util.concurrent.atomic.AtomicLong; 19 | 20 | /** 21 | * ID generator for commit log segments. 22 | * 23 | * @author benjamin 24 | * 25 | */ 26 | final class IdFactory { 27 | 28 | /** 29 | * The current ID. 30 | */ 31 | private static final AtomicLong nextId = new AtomicLong(System.currentTimeMillis()); 32 | 33 | /** 34 | * Returns the next ID available. 35 | * 36 | * @return the next ID available. 37 | */ 38 | public static long nextId() { 39 | return nextId.incrementAndGet(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/commitlog/PeriodicWriteExecutor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.commitlog; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.commitlog.CommitLog.FlushTask; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * A WriteExecutor that flush the data to disk periodically. 25 | * The period is specified by the commitLogFlushPeriodInMillis from the database configuration. 26 | * 27 | * @author Benjamin 28 | * 29 | */ 30 | final class PeriodicWriteExecutor extends AbstractWriteExecutor { 31 | 32 | 33 | public PeriodicWriteExecutor(Configuration configuration, FlushTask flushTask) { 34 | 35 | super(configuration, flushTask); 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | @Override 42 | protected WriteThreadPoolExecutor createWriteThreadPoolExecutor(Configuration configuration, 43 | String name, 44 | FlushTask flushTask) { 45 | return new PeriodicExecutorService(configuration, name, flushTask); 46 | } 47 | 48 | /** 49 | * ScheduledThreadPoolExecutor that flush the data to disk periodically. 50 | * 51 | */ 52 | private static final class PeriodicExecutorService extends WriteThreadPoolExecutor { 53 | 54 | public PeriodicExecutorService(Configuration configuration, String name, FlushTask flushTask) { 55 | 56 | super(name, flushTask); 57 | 58 | long flushPeriodInMillis = configuration.getCommitLogFlushPeriodInMillis(); 59 | scheduleAtFixedRate(flushTask, flushPeriodInMillis, flushPeriodInMillis, TimeUnit.MILLISECONDS); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/commitlog/WriteExecutor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.commitlog; 17 | 18 | import io.horizondb.db.metrics.Monitorable; 19 | 20 | import com.google.common.util.concurrent.ListenableFuture; 21 | 22 | /** 23 | * An object that executes writes to the commit log. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | interface WriteExecutor extends Monitorable { 29 | 30 | /** 31 | * Executes the specified write task. 32 | * 33 | * @param writeTask the write task to execute. 34 | * @return a Future representing pending completion of the task 35 | */ 36 | ListenableFuture executeWrite(CommitLog.WriteTask writeTask); 37 | 38 | /** 39 | * Shutdown this WriteExecutor 40 | * @throws InterruptedException if the thread is interrupted 41 | */ 42 | void shutdown() throws InterruptedException; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/databases/DatabaseCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.databases; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.cache.AbstractCache; 20 | 21 | import com.google.common.cache.CacheBuilder; 22 | 23 | /** 24 | * A Cache for databases. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | final class DatabaseCache extends AbstractCache { 30 | 31 | /** 32 | * Creates a DatabaseCache to cache the databases. 33 | * 34 | * @param configuration the database configuration. 35 | */ 36 | public DatabaseCache(Configuration configuration) { 37 | 38 | super(configuration); 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | @Override 45 | protected CacheBuilder newBuilder(Configuration configuration) { 46 | 47 | return CacheBuilder.newBuilder() 48 | .maximumSize(configuration.getDatabaseCacheMaximumSize()) 49 | .recordStats(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/databases/DatabaseManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.databases; 17 | 18 | import io.horizondb.db.Component; 19 | import io.horizondb.db.HorizonDBException; 20 | import io.horizondb.db.series.TimeSeriesManager; 21 | import io.horizondb.model.schema.DatabaseDefinition; 22 | 23 | import java.io.IOException; 24 | 25 | /** 26 | * Databases manager. 27 | */ 28 | public interface DatabaseManager extends Component { 29 | 30 | /** 31 | * Creates the database with the specified definition. 32 | * 33 | * @param definition the database definition. 34 | * @param throwExceptionIfExists true if an exception must be thrown if the database already exists. 35 | * @throws IOException if an I/O problem occurs while creating the database. 36 | * @throws HorizonDBException if a database with the same name already exists and throwExceptionIfExists is 37 | * true. 38 | */ 39 | void createDatabase(DatabaseDefinition definition, 40 | boolean throwExceptionIfExists) throws IOException, HorizonDBException; 41 | 42 | /** 43 | * Returns the database with the specified name if it exists. 44 | * 45 | * @param name the database name. 46 | * @return the database with the specified name if it exists. 47 | * @throws IOException if an I/O problem occurs while retrieving the database. 48 | * @throws HorizonDBException if the database with the specified name does not exists. 49 | */ 50 | Database getDatabase(String name) throws IOException, HorizonDBException; 51 | 52 | /** 53 | * Returns the TimeSeriesManager used by this DatabaseManager. 54 | * 55 | * @return the TimeSeriesManager used by this DatabaseManager. 56 | */ 57 | TimeSeriesManager getTimeSeriesManager(); 58 | 59 | /** 60 | * Drops the specified database. 61 | * @param name the name of the database to drop. 62 | * @param throwExceptionIfDoesNotExist true if an exception must be thrown if the time series does not exists. 63 | * @throws IOException if an I/O problem occurs while dropping the database. 64 | * @throws HorizonDBException if the database does not exists. 65 | */ 66 | void dropDatabase(String name, 67 | boolean throwExceptionIfDoesNotExist) throws IOException, HorizonDBException; 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/databases/InMemoryDatabaseManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.databases; 15 | 16 | import java.io.IOException; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.btree.InMemoryNodeManager; 20 | import io.horizondb.db.btree.NodeManager; 21 | import io.horizondb.db.series.TimeSeriesManager; 22 | import io.horizondb.model.schema.DatabaseDefinition; 23 | 24 | /** 25 | * DatabaseManager that store all data in memory. 26 | */ 27 | public final class InMemoryDatabaseManager extends AbstractDatabaseManager { 28 | 29 | /** 30 | * Creates a new InMemoryDatabaseManager that will used the specified configuration. 31 | * 32 | * @param configuration the database configuration 33 | * @param timeSeriesManager the time series manager 34 | */ 35 | public InMemoryDatabaseManager(Configuration configuration, TimeSeriesManager timeSeriesManager) { 36 | super(configuration, timeSeriesManager); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | protected NodeManager createNodeManager(Configuration configuration, String name) throws IOException { 44 | return new InMemoryNodeManager<>(name); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/metrics/CacheMetrics.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.metrics; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | import com.codahale.metrics.Gauge; 22 | import com.codahale.metrics.Metric; 23 | import com.codahale.metrics.MetricRegistry; 24 | import com.codahale.metrics.MetricSet; 25 | import com.google.common.cache.Cache; 26 | 27 | /** 28 | * The metrics for a cache instance. 29 | * 30 | * @author Benjamin 31 | * 32 | */ 33 | public final class CacheMetrics implements MetricSet { 34 | 35 | /** 36 | * The name of the loading cache. 37 | */ 38 | private final String name; 39 | 40 | /** 41 | * The cache. 42 | */ 43 | private final Cache cache; 44 | 45 | public CacheMetrics(String name, Cache cache) { 46 | 47 | this.name = name; 48 | this.cache = cache; 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | @Override 55 | public Map getMetrics() { 56 | 57 | Map map = new HashMap(); 58 | 59 | map.put(MetricRegistry.name(this.name, "size"), new Gauge() { 60 | 61 | /** 62 | * {@inheritDoc} 63 | */ 64 | @SuppressWarnings("boxing") 65 | @Override 66 | public Long getValue() { 67 | return CacheMetrics.this.cache.size(); 68 | } 69 | }); 70 | 71 | map.put(MetricRegistry.name(this.name, "requestCount"), new Gauge() { 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @SuppressWarnings("boxing") 77 | @Override 78 | public Long getValue() { 79 | return CacheMetrics.this.cache.stats().requestCount(); 80 | } 81 | }); 82 | 83 | map.put(MetricRegistry.name(this.name, "hitRate"), new Gauge() { 84 | 85 | /** 86 | * {@inheritDoc} 87 | */ 88 | @SuppressWarnings("boxing") 89 | @Override 90 | public Double getValue() { 91 | return CacheMetrics.this.cache.stats().hitRate(); 92 | } 93 | }); 94 | 95 | map.put(MetricRegistry.name(this.name, "evictionCount"), new Gauge() { 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | @SuppressWarnings("boxing") 101 | @Override 102 | public Long getValue() { 103 | return CacheMetrics.this.cache.stats().evictionCount(); 104 | } 105 | }); 106 | 107 | return map; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/metrics/Monitorable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.metrics; 17 | 18 | import com.codahale.metrics.MetricRegistry; 19 | 20 | /** 21 | * Allow a component to register and unregister metrics. 22 | * 23 | * @author Benjamin 24 | * 25 | */ 26 | public interface Monitorable extends Nameable { 27 | 28 | /** 29 | * Register the metrics of this Monitorable object. 30 | * 31 | * @param registry the registry to which the metrics must be registered. 32 | */ 33 | void register(MetricRegistry registry); 34 | 35 | /** 36 | * Unregister the metrics of this Monitorable object. 37 | * 38 | * @param registry the registry from which the metrics must be unregistered. 39 | */ 40 | void unregister(MetricRegistry registry); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/metrics/Nameable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.metrics; 17 | 18 | /** 19 | * Force instance to have a name that can be used in error message or in JMX. 20 | * 21 | * @author Benjamin 22 | * 23 | */ 24 | public interface Nameable { 25 | 26 | /** 27 | * Returns this instance name. 28 | * 29 | * @return this instance name. 30 | */ 31 | String getName(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/metrics/PrefixFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.metrics; 17 | 18 | import com.codahale.metrics.Metric; 19 | import com.codahale.metrics.MetricFilter; 20 | 21 | /** 22 | * Filter that matches the filters which have a name that starts with the specified prefix. 23 | * 24 | * @author Benjamin 25 | * 26 | */ 27 | public final class PrefixFilter implements MetricFilter { 28 | 29 | /** 30 | * The prefix to match. 31 | */ 32 | private final String prefix; 33 | 34 | /** 35 | * Creates a new PrefixFilter that matches the filters with a name starting with the specified prefix. 36 | * 37 | * @param prefix the prefix. 38 | */ 39 | public PrefixFilter(String prefix) { 40 | this.prefix = prefix; 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @Override 47 | public boolean matches(String name, Metric metric) { 48 | return name.startsWith(this.prefix); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/metrics/ThreadPoolExecutorMetrics.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.metrics; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import java.util.concurrent.ThreadPoolExecutor; 21 | 22 | import com.codahale.metrics.Gauge; 23 | import com.codahale.metrics.Metric; 24 | import com.codahale.metrics.MetricRegistry; 25 | import com.codahale.metrics.MetricSet; 26 | 27 | /** 28 | * The metrics for a ThreadPoolExecutor. 29 | * 30 | * @author Benjamin 31 | * 32 | */ 33 | public final class ThreadPoolExecutorMetrics implements MetricSet { 34 | 35 | /** 36 | * The name of the thread pool. 37 | */ 38 | private final String name; 39 | 40 | /** 41 | * The thread pool. 42 | */ 43 | private final ThreadPoolExecutor threadPool; 44 | 45 | public ThreadPoolExecutorMetrics(String name, ThreadPoolExecutor threadPool) { 46 | 47 | this.name = name; 48 | this.threadPool = threadPool; 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | @Override 55 | public Map getMetrics() { 56 | 57 | Map map = new HashMap(); 58 | 59 | map.put(MetricRegistry.name(this.name, "poolSize"), new Gauge() { 60 | 61 | /** 62 | * {@inheritDoc} 63 | */ 64 | @SuppressWarnings("boxing") 65 | @Override 66 | public Integer getValue() { 67 | return ThreadPoolExecutorMetrics.this.threadPool.getPoolSize(); 68 | } 69 | }); 70 | 71 | map.put(MetricRegistry.name(this.name, "activeCount"), new Gauge() { 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @SuppressWarnings("boxing") 77 | @Override 78 | public Integer getValue() { 79 | return ThreadPoolExecutorMetrics.this.threadPool.getActiveCount(); 80 | } 81 | }); 82 | 83 | map.put(MetricRegistry.name(this.name, "completedTaskCount"), new Gauge() { 84 | 85 | /** 86 | * {@inheritDoc} 87 | */ 88 | @SuppressWarnings("boxing") 89 | @Override 90 | public Long getValue() { 91 | return ThreadPoolExecutorMetrics.this.threadPool.getCompletedTaskCount(); 92 | } 93 | }); 94 | 95 | map.put(MetricRegistry.name(this.name, "pendingTaskCount"), new Gauge() { 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | @SuppressWarnings("boxing") 101 | @Override 102 | public Long getValue() { 103 | 104 | ThreadPoolExecutor pool = ThreadPoolExecutorMetrics.this.threadPool; 105 | 106 | return pool.getTaskCount() - pool.getActiveCount() - pool.getCompletedTaskCount(); 107 | } 108 | }); 109 | 110 | return map; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/ChunkedRecordSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.model.protocol.DataHeaderPayload; 17 | import io.horizondb.model.protocol.Msg; 18 | import io.horizondb.model.protocol.MsgHeader; 19 | import io.horizondb.model.protocol.OpCode; 20 | import io.horizondb.model.protocol.Payload; 21 | import io.horizondb.model.schema.RecordSetDefinition; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import io.netty.handler.stream.ChunkedInput; 24 | 25 | /** 26 | * @author Benjamin 27 | * 28 | */ 29 | public class ChunkedRecordSet implements ChunkedInput> { 30 | 31 | /** 32 | * The request header 33 | */ 34 | private final MsgHeader requestHeader; 35 | 36 | /** 37 | * The record set definition 38 | */ 39 | private final RecordSetDefinition definition; 40 | 41 | /** 42 | * The data chunks 43 | */ 44 | private final ChunkedRecordStream recordStream; 45 | 46 | /** 47 | * true if this is the start of the input. 48 | */ 49 | private boolean isStartOfInput = true; 50 | 51 | /** 52 | * Creates a new ChunkedRecordSet. 53 | * 54 | * @param requestHeader the request header 55 | * @param definition the time series definition for which data is returned 56 | * @param recordStream the record stream 57 | */ 58 | public ChunkedRecordSet(MsgHeader requestHeader, RecordSetDefinition definition, ChunkedRecordStream recordStream) { 59 | 60 | this.requestHeader = requestHeader; 61 | this.definition = definition; 62 | this.recordStream = recordStream; 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | */ 68 | @Override 69 | public void close() throws Exception { 70 | this.recordStream.close(); 71 | } 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @Override 77 | public boolean isEndOfInput() throws Exception { 78 | return this.recordStream.isEndOfInput(); 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | */ 84 | @Override 85 | public Msg readChunk(ChannelHandlerContext arg0) throws Exception { 86 | 87 | if (this.isStartOfInput) { 88 | 89 | this.isStartOfInput = false; 90 | 91 | Payload payload = new DataHeaderPayload(this.definition); 92 | return Msg.newResponseMsg(this.requestHeader, OpCode.DATA_HEADER, payload); 93 | } 94 | 95 | return this.recordStream.readChunk(arg0); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/CreateDatabaseOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.operations; 17 | 18 | import io.horizondb.db.HorizonDBException; 19 | import io.horizondb.db.Operation; 20 | import io.horizondb.db.OperationContext; 21 | import io.horizondb.db.databases.DatabaseManager; 22 | import io.horizondb.model.protocol.CreateDatabasePayload; 23 | import io.horizondb.model.protocol.Msg; 24 | import io.horizondb.model.protocol.MsgHeader; 25 | import io.horizondb.model.protocol.Msgs; 26 | import io.horizondb.model.protocol.OpCode; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * @author Benjamin 32 | * 33 | */ 34 | final class CreateDatabaseOperation implements Operation { 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | @Override 40 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 41 | 42 | CreateDatabasePayload payload = Msgs.getPayload(request); 43 | 44 | DatabaseManager manager = context.getDatabaseManager(); 45 | manager.createDatabase(payload.getDefinition(), context.isReplay()); 46 | 47 | return Msg.emptyMsg(MsgHeader.newResponseHeader(request.getHeader(), OpCode.NOOP, 0, 0)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/CreateTimeSeriesOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.operations; 17 | 18 | import io.horizondb.db.HorizonDBException; 19 | import io.horizondb.db.Operation; 20 | import io.horizondb.db.OperationContext; 21 | import io.horizondb.db.databases.Database; 22 | import io.horizondb.db.databases.DatabaseManager; 23 | import io.horizondb.model.protocol.CreateTimeSeriesPayload; 24 | import io.horizondb.model.protocol.Msg; 25 | import io.horizondb.model.protocol.Msgs; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * @author Benjamin 31 | * 32 | */ 33 | final class CreateTimeSeriesOperation implements Operation { 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 40 | 41 | CreateTimeSeriesPayload payload = Msgs.getPayload(request); 42 | 43 | DatabaseManager manager = context.getDatabaseManager(); 44 | Database database = manager.getDatabase(payload.getDatabaseName()); 45 | database.createTimeSeries(payload.getDefinition(), !context.isReplay()); 46 | 47 | return Msgs.newCreateTimeSeriesResponse(request); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/DropDatabaseOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.Operation; 18 | import io.horizondb.db.OperationContext; 19 | import io.horizondb.db.databases.DatabaseManager; 20 | import io.horizondb.model.protocol.DropDatabasePayload; 21 | import io.horizondb.model.protocol.Msg; 22 | import io.horizondb.model.protocol.MsgHeader; 23 | import io.horizondb.model.protocol.Msgs; 24 | import io.horizondb.model.protocol.OpCode; 25 | 26 | import java.io.IOException; 27 | 28 | /** 29 | */ 30 | final class DropDatabaseOperation implements Operation { 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | @Override 36 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 37 | 38 | DropDatabasePayload payload = Msgs.getPayload(request); 39 | 40 | DatabaseManager manager = context.getDatabaseManager(); 41 | manager.dropDatabase(payload.getDatabase(), true); 42 | 43 | return Msg.emptyMsg(MsgHeader.newResponseHeader(request.getHeader(), OpCode.NOOP, 0, 0)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/DropTimeSeriesOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.Operation; 18 | import io.horizondb.db.OperationContext; 19 | import io.horizondb.db.databases.Database; 20 | import io.horizondb.db.databases.DatabaseManager; 21 | import io.horizondb.model.protocol.DropTimeSeriesPayload; 22 | import io.horizondb.model.protocol.Msg; 23 | import io.horizondb.model.protocol.MsgHeader; 24 | import io.horizondb.model.protocol.Msgs; 25 | import io.horizondb.model.protocol.OpCode; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | */ 31 | final class DropTimeSeriesOperation implements Operation { 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | @Override 37 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 38 | 39 | DropTimeSeriesPayload payload = Msgs.getPayload(request); 40 | 41 | DatabaseManager manager = context.getDatabaseManager(); 42 | Database database = manager.getDatabase(payload.getDatabase()); 43 | database.dropTimeSeries(payload.getTimeSeries()); 44 | 45 | return Msg.emptyMsg(MsgHeader.newResponseHeader(request.getHeader(), OpCode.NOOP, 0, 0)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/InsertOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.Operation; 18 | import io.horizondb.db.OperationContext; 19 | import io.horizondb.db.databases.Database; 20 | import io.horizondb.db.series.TimeSeries; 21 | import io.horizondb.model.core.blocks.BinaryDataBlock; 22 | import io.horizondb.model.protocol.InsertPayload; 23 | import io.horizondb.model.protocol.Msg; 24 | import io.horizondb.model.protocol.MsgHeader; 25 | import io.horizondb.model.protocol.Msgs; 26 | import io.horizondb.model.protocol.OpCode; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * Operation that handle INSERT operations. 32 | */ 33 | final class InsertOperation implements Operation { 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 40 | 41 | InsertPayload payload = Msgs.getPayload(request); 42 | 43 | Database database = context.getDatabaseManager().getDatabase(payload.getDatabase()); 44 | 45 | TimeSeries series = database.getTimeSeries(payload.getSeries()); 46 | 47 | BinaryDataBlock block = new BinaryDataBlock(series.getDefinition().newBinaryBlockHeader()); 48 | block.fill(payload.getBuffer()); 49 | 50 | series.write(block, context.getFuture(), context.isReplay()); 51 | 52 | return Msg.emptyMsg(MsgHeader.newResponseHeader(request.getHeader(), OpCode.NOOP, 0, 0)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/Operations.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.db.Operation; 17 | import io.horizondb.model.protocol.OpCode; 18 | 19 | import java.util.EnumMap; 20 | import java.util.Map; 21 | 22 | /** 23 | * The mapping between operation code and the actual operations. 24 | * 25 | */ 26 | public final class Operations { 27 | 28 | /** 29 | * The Operations instance. 30 | */ 31 | private static final Operations INSTANCE = new Operations(); 32 | 33 | /** 34 | * The mapping between the operation code and the action to execute. 35 | */ 36 | private final Map operations; 37 | 38 | /** 39 | * Returns the Operation associated to the specified operation code. 40 | * 41 | * @param opCode the operation code 42 | * @return the Operation associated to the specified code or null 43 | * if the code is unknown 44 | */ 45 | public static Operation getOperationFor(OpCode opCode) { 46 | 47 | return INSTANCE.operations.get(opCode); 48 | } 49 | 50 | /** 51 | * Creates a new Operations instance. 52 | */ 53 | private Operations() { 54 | 55 | this.operations = new EnumMap<>(OpCode.class); 56 | this.operations.put(OpCode.CREATE_DATABASE, new CreateDatabaseOperation()); 57 | this.operations.put(OpCode.USE_DATABASE, new UseDatabaseOperation()); 58 | this.operations.put(OpCode.CREATE_TIMESERIES, new CreateTimeSeriesOperation()); 59 | this.operations.put(OpCode.SELECT, new SelectOperation()); 60 | this.operations.put(OpCode.INSERT, new InsertOperation()); 61 | this.operations.put(OpCode.DROP_TIMESERIES, new DropTimeSeriesOperation()); 62 | this.operations.put(OpCode.DROP_DATABASE, new DropDatabaseOperation()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/SelectOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.operations; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.Operation; 18 | import io.horizondb.db.OperationContext; 19 | import io.horizondb.db.databases.Database; 20 | import io.horizondb.db.series.TimeSeries; 21 | import io.horizondb.model.core.Predicate; 22 | import io.horizondb.model.core.Projection; 23 | import io.horizondb.model.core.Record; 24 | import io.horizondb.model.core.ResourceIterator; 25 | import io.horizondb.model.protocol.Msg; 26 | import io.horizondb.model.protocol.Msgs; 27 | import io.horizondb.model.protocol.SelectPayload; 28 | 29 | import java.io.IOException; 30 | 31 | /** 32 | * Operation used to select data. 33 | */ 34 | final class SelectOperation implements Operation { 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | @Override 40 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 41 | 42 | SelectPayload payload = Msgs.getPayload(request); 43 | 44 | Database database = context.getDatabaseManager().getDatabase(payload.getDatabaseName()); 45 | 46 | TimeSeries series = database.getTimeSeries(payload.getSeriesName()); 47 | 48 | Projection projection = payload.getProjection(); 49 | Predicate predicate = payload.getPredicate(); 50 | try (ResourceIterator iterator = series.read(projection, predicate)) { 51 | return new ChunkedRecordSet(request.getHeader(), 52 | projection.getDefinition(series.getDefinition()), 53 | new ChunkedRecordStream(request.getHeader(), iterator)); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/operations/UseDatabaseOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.operations; 17 | 18 | import io.horizondb.db.HorizonDBException; 19 | import io.horizondb.db.Operation; 20 | import io.horizondb.db.OperationContext; 21 | import io.horizondb.db.databases.Database; 22 | import io.horizondb.db.databases.DatabaseManager; 23 | import io.horizondb.model.protocol.Msg; 24 | import io.horizondb.model.protocol.Msgs; 25 | import io.horizondb.model.protocol.OpCode; 26 | import io.horizondb.model.protocol.SetDatabasePayload; 27 | import io.horizondb.model.protocol.UseDatabasePayload; 28 | 29 | import java.io.IOException; 30 | 31 | /** 32 | * @author Benjamin 33 | * 34 | */ 35 | final class UseDatabaseOperation implements Operation { 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | @Override 41 | public Object perform(OperationContext context, Msg request) throws IOException, HorizonDBException { 42 | 43 | UseDatabasePayload payload = Msgs.getPayload(request); 44 | 45 | DatabaseManager manager = context.getDatabaseManager(); 46 | Database database = manager.getDatabase(payload.getDatabase()); 47 | 48 | return Msg.newResponseMsg(request.getHeader(), OpCode.SET_DATABASE, new SetDatabasePayload(database.getDefinition())); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/BadHqlGrammarException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.model.ErrorCodes; 18 | 19 | /** 20 | * Exception thrown by the HQL parser when an HQL query is invalid. 21 | */ 22 | public final class BadHqlGrammarException extends HorizonDBException { 23 | 24 | /** 25 | * Serial UID 26 | */ 27 | private static final long serialVersionUID = 8906102712317030814L; 28 | 29 | public BadHqlGrammarException(String query, int lineNumber, int charPosition, String message) { 30 | super(ErrorCodes.INVALID_QUERY, errorMessage(query, lineNumber, charPosition, message)); 31 | } 32 | 33 | public BadHqlGrammarException(String message) { 34 | super(ErrorCodes.INVALID_QUERY, message); 35 | } 36 | 37 | /** 38 | * Creates the exception error message. 39 | * 40 | * @param query the invalid query 41 | * @param lineNumber the line where the error occurred 42 | * @param charPosition the char position within the line 43 | * @return error message 44 | */ 45 | private static String errorMessage(String query, int lineNumber, int charPosition, String message) { 46 | 47 | return new StringBuilder().append("The query: '") 48 | .append(query) 49 | .append("' has an error in line ") 50 | .append(lineNumber) 51 | .append(" character ") 52 | .append(charPosition) 53 | .append(": ") 54 | .append(message) 55 | .toString(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser; 15 | 16 | import org.antlr.v4.runtime.BaseErrorListener; 17 | import org.antlr.v4.runtime.RecognitionException; 18 | import org.antlr.v4.runtime.Recognizer; 19 | import org.antlr.v4.runtime.misc.NotNull; 20 | import org.antlr.v4.runtime.misc.Nullable; 21 | 22 | /** 23 | * ErrorListener used to convert the syntax errors of an HQL query into SyntaxException. 24 | */ 25 | public final class ErrorHandler extends BaseErrorListener { 26 | 27 | /** 28 | * {@inheritDoc} 29 | */ 30 | @Override 31 | public void syntaxError(@NotNull Recognizer recognizer, 32 | @Nullable Object offendingSymbol, 33 | int line, 34 | int charPositionInLine, 35 | @NotNull String msg, 36 | @Nullable RecognitionException e) { 37 | 38 | throw new SyntaxException(line, charPositionInLine, msg); 39 | } 40 | 41 | /** 42 | * Information about an error that occurred during parsing. 43 | */ 44 | public static final class SyntaxException extends RuntimeException { 45 | 46 | /** 47 | * The serial version UID. 48 | */ 49 | private static final long serialVersionUID = -2783921035310035769L; 50 | 51 | /** 52 | * The number of the line where the error occurred. 53 | */ 54 | private final int lineNumber; 55 | 56 | /** 57 | * The position of the char where the error occurred. 58 | */ 59 | private final int charPosition; 60 | 61 | /** 62 | * @param lineNumber 63 | * @param charPosition the position of the char where the error occurred 64 | * @param message 65 | */ 66 | public SyntaxException(int lineNumber, int charPosition, String message) { 67 | 68 | super(message); 69 | this.lineNumber = lineNumber; 70 | this.charPosition = charPosition; 71 | } 72 | 73 | /** 74 | * Returns the line number. 75 | * 76 | * @return the line number. 77 | */ 78 | public int getLineNumber() { 79 | return this.lineNumber; 80 | } 81 | 82 | /** 83 | * Returns the position of the char where the error occurred. 84 | * @return the position of the char where the error occurred 85 | */ 86 | public int getCharPosition() { 87 | return this.charPosition; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/MsgBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser; 15 | 16 | import java.io.IOException; 17 | 18 | import io.horizondb.db.HorizonDBException; 19 | import io.horizondb.model.protocol.Msg; 20 | 21 | /** 22 | * Builder used to build Msg instances. 23 | */ 24 | public interface MsgBuilder extends HqlListener { 25 | 26 | /** 27 | * Builds a new message instance. 28 | * 29 | * @return a new message instance 30 | * @throws IOException if an I/O problem occurs while building the message 31 | * @throws HorizonDBException if a problem occurs while building the message 32 | */ 33 | public Msg build() throws IOException, HorizonDBException; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/builders/CreateDatabaseMsgBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser.builders; 15 | 16 | import java.io.IOException; 17 | 18 | import io.horizondb.db.parser.HqlBaseListener; 19 | import io.horizondb.db.parser.HqlParser.CreateDatabaseContext; 20 | import io.horizondb.db.parser.MsgBuilder; 21 | import io.horizondb.model.protocol.CreateDatabasePayload; 22 | import io.horizondb.model.protocol.Msg; 23 | import io.horizondb.model.protocol.MsgHeader; 24 | import io.horizondb.model.protocol.OpCode; 25 | import io.horizondb.model.protocol.Payload; 26 | import io.horizondb.model.schema.DatabaseDefinition; 27 | 28 | import org.antlr.v4.runtime.misc.NotNull; 29 | 30 | /** 31 | * Builder for CreateDatabaseRequest instances. 32 | * 33 | */ 34 | final class CreateDatabaseMsgBuilder extends HqlBaseListener implements MsgBuilder { 35 | 36 | /** 37 | * The original request header. 38 | */ 39 | private final MsgHeader requestHeader; 40 | 41 | /** 42 | * The definition of the database that must be created. 43 | */ 44 | private DatabaseDefinition definition; 45 | 46 | /** 47 | * Creates a new CreateDatabaseRequestBuilder instance. 48 | * 49 | * @param requestHeader the original request header 50 | */ 51 | public CreateDatabaseMsgBuilder(MsgHeader requestHeader) { 52 | 53 | this.requestHeader = requestHeader; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public void enterCreateDatabase(@NotNull CreateDatabaseContext ctx) { 61 | 62 | String databaseName = ctx.ID().getText(); 63 | this.definition = new DatabaseDefinition(databaseName); 64 | } 65 | 66 | /** 67 | * {@inheritDoc} 68 | */ 69 | @Override 70 | public Msg build() throws IOException { 71 | 72 | Payload payload = new CreateDatabasePayload(this.definition); 73 | return Msg.newRequestMsg(this.requestHeader, OpCode.CREATE_DATABASE, payload); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/builders/DropDatabaseMsgBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser.builders; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.databases.DatabaseManager; 18 | import io.horizondb.db.parser.BadHqlGrammarException; 19 | import io.horizondb.db.parser.HqlBaseListener; 20 | import io.horizondb.db.parser.HqlParser.DropDatabaseContext; 21 | import io.horizondb.db.parser.MsgBuilder; 22 | import io.horizondb.model.protocol.DropDatabasePayload; 23 | import io.horizondb.model.protocol.Msg; 24 | import io.horizondb.model.protocol.MsgHeader; 25 | import io.horizondb.model.protocol.OpCode; 26 | import io.horizondb.model.protocol.Payload; 27 | 28 | import java.io.IOException; 29 | 30 | import org.antlr.v4.runtime.misc.NotNull; 31 | 32 | /** 33 | * Builder for messages requesting the deletion of a database. 34 | */ 35 | final class DropDatabaseMsgBuilder extends HqlBaseListener implements MsgBuilder { 36 | 37 | /** 38 | * The database manager. 39 | */ 40 | private final DatabaseManager databaseManager; 41 | 42 | /** 43 | * The original request header. 44 | */ 45 | private final MsgHeader requestHeader; 46 | 47 | /** 48 | * The database. 49 | */ 50 | private String currentDatabase; 51 | 52 | /** 53 | * The database. 54 | */ 55 | private String databaseName; 56 | 57 | /** 58 | * Creates a new DropDatabaseMsgBuilder instance. 59 | * 60 | * @param databaseManager the database manager used to retrieve the database 61 | * @param requestHeader the original request header 62 | * @param databaseName the name of the time series database 63 | */ 64 | public DropDatabaseMsgBuilder(DatabaseManager databaseManager, 65 | MsgHeader requestHeader, 66 | String databaseName) { 67 | 68 | this.databaseManager = databaseManager; 69 | this.requestHeader = requestHeader; 70 | this.currentDatabase = databaseName; 71 | } 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @Override 77 | public void enterDropDatabase(@NotNull DropDatabaseContext ctx) { 78 | 79 | this.databaseName = ctx.ID().getText(); 80 | } 81 | 82 | /** 83 | * {@inheritDoc} 84 | */ 85 | @Override 86 | public Msg build() throws IOException, HorizonDBException { 87 | 88 | if (this.currentDatabase.equals(this.databaseName)) { 89 | 90 | String msg = String.format("Cannot drop %s as it is the currently used database." 91 | + " You must first switch to an other database.", 92 | this.databaseName); 93 | throw new BadHqlGrammarException(msg); 94 | } 95 | 96 | // Checks that the database exists. 97 | this.databaseManager.getDatabase(this.databaseName); 98 | 99 | Payload payload = new DropDatabasePayload(this.databaseName); 100 | return Msg.newRequestMsg(this.requestHeader, OpCode.DROP_DATABASE, payload); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/builders/DropTimeSeriesMsgBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser.builders; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.db.databases.DatabaseManager; 18 | import io.horizondb.db.parser.HqlBaseListener; 19 | import io.horizondb.db.parser.HqlParser.DropTimeSeriesContext; 20 | import io.horizondb.db.parser.MsgBuilder; 21 | import io.horizondb.model.protocol.DropTimeSeriesPayload; 22 | import io.horizondb.model.protocol.Msg; 23 | import io.horizondb.model.protocol.MsgHeader; 24 | import io.horizondb.model.protocol.OpCode; 25 | import io.horizondb.model.protocol.Payload; 26 | 27 | import java.io.IOException; 28 | 29 | import org.antlr.v4.runtime.misc.NotNull; 30 | 31 | /** 32 | * Builder for messages requesting the deletion of a time series. 33 | */ 34 | final class DropTimeSeriesMsgBuilder extends HqlBaseListener implements MsgBuilder { 35 | 36 | /** 37 | * The database manager. 38 | */ 39 | private final DatabaseManager databaseManager; 40 | 41 | /** 42 | * The original request header. 43 | */ 44 | private final MsgHeader requestHeader; 45 | 46 | /** 47 | * The time series database. 48 | */ 49 | private String databaseName; 50 | 51 | /** 52 | * The time series name. 53 | */ 54 | private String timeSeriesName; 55 | 56 | /** 57 | * Creates a new DropTimeSeriesMsgBuilder instance. 58 | * 59 | * @param databaseManager the database manager used to retrieve the database 60 | * @param requestHeader the original request header 61 | * @param databaseName the name of the time series database 62 | */ 63 | public DropTimeSeriesMsgBuilder(DatabaseManager databaseManager, 64 | MsgHeader requestHeader, 65 | String databaseName) { 66 | 67 | this.databaseManager = databaseManager; 68 | this.requestHeader = requestHeader; 69 | this.databaseName = databaseName; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public void enterDropTimeSeries(@NotNull DropTimeSeriesContext ctx) { 77 | 78 | if (ctx.databaseName() != null) { 79 | this.databaseName = ctx.databaseName().getText(); 80 | } 81 | this.timeSeriesName = ctx.timeSeriesName().getText(); 82 | } 83 | 84 | /** 85 | * {@inheritDoc} 86 | */ 87 | @Override 88 | public Msg build() throws IOException, HorizonDBException { 89 | 90 | // Checks that the database exists. 91 | this.databaseManager.getDatabase(this.databaseName); 92 | 93 | Payload payload = new DropTimeSeriesPayload(this.databaseName, this.timeSeriesName); 94 | return Msg.newRequestMsg(this.requestHeader, OpCode.DROP_TIMESERIES, payload); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/builders/PredicateBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser.builders; 15 | 16 | import io.horizondb.db.HorizonDBException; 17 | import io.horizondb.model.core.Predicate; 18 | import io.horizondb.model.schema.TimeSeriesDefinition; 19 | 20 | /** 21 | * A Builder for predicates. 22 | */ 23 | public interface PredicateBuilder { 24 | 25 | /** 26 | * Builds a new Predicate instance. 27 | * 28 | * @param definition the definition of the time series on which this predicate must be applied 29 | * @return a new Predicate instance 30 | * @throws HorizonDBException if the predicate cannot be build due to some invalid values. 31 | */ 32 | Predicate build(TimeSeriesDefinition definition) throws HorizonDBException; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/parser/builders/UseDatabaseMsgBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.parser.builders; 15 | 16 | import java.io.IOException; 17 | 18 | import io.horizondb.db.parser.HqlBaseListener; 19 | import io.horizondb.db.parser.HqlParser.UseDatabaseContext; 20 | import io.horizondb.db.parser.MsgBuilder; 21 | import io.horizondb.model.protocol.Msg; 22 | import io.horizondb.model.protocol.MsgHeader; 23 | import io.horizondb.model.protocol.OpCode; 24 | import io.horizondb.model.protocol.Payload; 25 | import io.horizondb.model.protocol.UseDatabasePayload; 26 | 27 | import org.antlr.v4.runtime.misc.NotNull; 28 | 29 | /** 30 | * Builder for UseDatabaseMsg instances. 31 | * 32 | * @author Benjamin 33 | * 34 | */ 35 | final class UseDatabaseMsgBuilder extends HqlBaseListener implements MsgBuilder { 36 | 37 | /** 38 | * The original request header. 39 | */ 40 | private final MsgHeader requestHeader; 41 | 42 | /** 43 | * The name of the database that must be used. 44 | */ 45 | private String databaseName; 46 | 47 | /** 48 | * Creates a new CreateDatabaseRequestBuilder instance. 49 | * 50 | * @param requestHeader the original request header 51 | */ 52 | public UseDatabaseMsgBuilder(MsgHeader requestHeader) { 53 | 54 | this.requestHeader = requestHeader; 55 | } 56 | 57 | /** 58 | * {@inheritDoc} 59 | */ 60 | @Override 61 | public void enterUseDatabase(@NotNull UseDatabaseContext ctx) { 62 | this.databaseName = ctx.ID().getText(); 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | */ 68 | @Override 69 | public Msg build() throws IOException { 70 | 71 | Payload payload = new UseDatabasePayload(this.databaseName); 72 | return Msg.newRequestMsg(this.requestHeader, OpCode.USE_DATABASE, payload); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/FlushListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | /** 17 | * Listener used to receive flush notification. 18 | */ 19 | public interface FlushListener { 20 | 21 | /** 22 | * Notification that the flush has been performed. 23 | */ 24 | void afterFlush(); 25 | } -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/InMemoryTimeSeriesManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import java.io.IOException; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.btree.BTreeStore; 20 | import io.horizondb.model.schema.TimeSeriesDefinition; 21 | 22 | /** 23 | * A TimeSeriesManager that store its data in memory. 24 | */ 25 | public final class InMemoryTimeSeriesManager extends AbstractTimeSeriesManager { 26 | 27 | public InMemoryTimeSeriesManager(TimeSeriesPartitionManager partitionManager, Configuration configuration) { 28 | super(partitionManager, configuration); 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | @Override 35 | protected BTreeStore createBTreeStore(Configuration configuration, 36 | int branchingFactor) 37 | throws IOException { 38 | return BTreeStore.newInMemoryStore(getName(), branchingFactor); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/InMemoryTimeSeriesPartitionManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.Configuration; 17 | import io.horizondb.db.btree.BTreeStore; 18 | 19 | import java.io.IOException; 20 | 21 | /** 22 | * TimeSeriesPartitionManager that stores its data in memory. 23 | */ 24 | public final class InMemoryTimeSeriesPartitionManager extends AbstractTimeSeriesPartitionManager { 25 | 26 | /** 27 | * Creates a new InMemoryTimeSeriesPartitionManager. 28 | * 29 | * @param configuration the database configuration 30 | */ 31 | public InMemoryTimeSeriesPartitionManager(Configuration configuration) { 32 | super(configuration); 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | protected BTreeStore createBTreeStore(Configuration configuration, 40 | int branchingFactor) throws IOException { 41 | return BTreeStore.newInMemoryStore(getName(), branchingFactor); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/MapKeyValueIterator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.btree.KeyValueIterator; 17 | 18 | import java.util.Iterator; 19 | import java.util.Map; 20 | import java.util.Map.Entry; 21 | import java.util.TreeMap; 22 | 23 | /** 24 | * KeyValueIterator that iterate over the data of a Map in the key ascending order. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | public final class MapKeyValueIterator, V> implements KeyValueIterator { 30 | 31 | /** 32 | * The iterator over the map entries. 33 | */ 34 | private final Iterator> iterator; 35 | 36 | /** 37 | * The current map entry. 38 | */ 39 | private Entry entry; 40 | 41 | /** 42 | * Creates a MapKeyValueIterator instance that will iterate over the entries of the specified 43 | * Map. 44 | * 45 | * @param map the key-value mapping on which the iterator will iterate in the key ascending order. 46 | */ 47 | public MapKeyValueIterator(Map map) { 48 | 49 | this.iterator = new TreeMap<>(map).entrySet().iterator(); 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | @Override 56 | public boolean next() { 57 | 58 | if (this.iterator.hasNext()) { 59 | 60 | this.entry = this.iterator.next(); 61 | return true; 62 | } 63 | 64 | return false; 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | @Override 71 | public K getKey() { 72 | return this.entry.getKey(); 73 | } 74 | 75 | /** 76 | * {@inheritDoc} 77 | */ 78 | @Override 79 | public V getValue() { 80 | return this.entry.getValue(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/MergingKeyValueIterator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.btree.KeyValueIterator; 17 | 18 | import java.io.IOException; 19 | import java.util.SortedMap; 20 | import java.util.TreeMap; 21 | 22 | /** 23 | * KeyValueIterator used to merge the results returned by multiple iterators. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public final class MergingKeyValueIterator, V> implements KeyValueIterator { 29 | 30 | /** 31 | * The sorted map used to sort the values returned by the iterators. 32 | */ 33 | private SortedMap> map = new TreeMap>(); 34 | 35 | /** 36 | * The next key and value to be returned. 37 | */ 38 | private KeyValueIterator next; 39 | 40 | /** 41 | * Creates a new MergingKeyValueIterator the will merge the results of the specified iterators. 42 | * 43 | * @param iterators the iterators 44 | * @throws IOException if an I/O problem occurs 45 | */ 46 | @SafeVarargs 47 | public MergingKeyValueIterator(KeyValueIterator... iterators) throws IOException { 48 | 49 | for (KeyValueIterator iterator : iterators) { 50 | if (iterator.next()) { 51 | this.map.put(iterator.getKey(), iterator); 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public boolean next() throws IOException { 61 | 62 | if (this.next != null && this.next.next()) { 63 | this.map.put(this.next.getKey(), this.next); 64 | } 65 | 66 | if (this.map.isEmpty()) { 67 | return false; 68 | } 69 | 70 | K key = this.map.firstKey(); 71 | this.next = this.map.remove(key); 72 | 73 | return true; 74 | } 75 | 76 | /** 77 | * {@inheritDoc} 78 | */ 79 | @Override 80 | public K getKey() { 81 | return this.next.getKey(); 82 | } 83 | 84 | /** 85 | * {@inheritDoc} 86 | */ 87 | @Override 88 | public V getValue() throws IOException { 89 | return this.next.getValue(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/OnDiskTimeSeriesManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import java.io.IOException; 17 | import java.nio.file.Path; 18 | 19 | import static io.horizondb.io.files.FileUtils.createDirectoriesIfNeeded; 20 | 21 | import io.horizondb.db.Configuration; 22 | import io.horizondb.db.HorizonDBFiles; 23 | import io.horizondb.db.btree.BTreeStore; 24 | import io.horizondb.io.files.FileUtils; 25 | import io.horizondb.model.schema.DatabaseDefinition; 26 | import io.horizondb.model.schema.TimeSeriesDefinition; 27 | 28 | /** 29 | * A TimeSeriesManager that store its data on disk. 30 | */ 31 | public final class OnDiskTimeSeriesManager extends AbstractTimeSeriesManager { 32 | 33 | public OnDiskTimeSeriesManager(TimeSeriesPartitionManager partitionManager, Configuration configuration) { 34 | super(partitionManager, configuration); 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | @Override 41 | protected BTreeStore createBTreeStore(Configuration configuration, 42 | int branchingFactor) 43 | throws IOException { 44 | 45 | createDirectoriesIfNeeded(HorizonDBFiles.getSystemDirectory(configuration)); 46 | 47 | Path timeSeriesFile = HorizonDBFiles.getTimeSeriesFile(configuration); 48 | 49 | return BTreeStore.newDiskStore(getName(), 50 | timeSeriesFile, 51 | branchingFactor, 52 | TimeSeriesId.getParser(), 53 | TimeSeriesDefinition.getParser()); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | protected void afterCreate(DatabaseDefinition databaseDefinition, 61 | TimeSeriesDefinition timeSeriesDefinition) throws IOException { 62 | 63 | Path timeSeriesDirectory = HorizonDBFiles.getTimeSeriesDirectory(this.configuration, 64 | databaseDefinition, 65 | timeSeriesDefinition); 66 | 67 | FileUtils.createDirectoriesIfNeeded(timeSeriesDirectory); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/OnDiskTimeSeriesPartitionManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.Configuration; 17 | import io.horizondb.db.btree.BTreeStore; 18 | 19 | import java.io.IOException; 20 | import java.nio.file.Files; 21 | import java.nio.file.Path; 22 | 23 | /** 24 | * TimeSeriesPartitionManager that stores its data on disk. 25 | */ 26 | public final class OnDiskTimeSeriesPartitionManager extends AbstractTimeSeriesPartitionManager { 27 | 28 | /** 29 | * Creates a new OnDiskTimeSeriesPartitionManager. 30 | * 31 | * @param configuration the database configuration 32 | */ 33 | public OnDiskTimeSeriesPartitionManager(Configuration configuration) { 34 | super(configuration); 35 | } 36 | 37 | /** 38 | * The name of the partition file. 39 | */ 40 | private static final String PARTITIONS_FILENAME = "partitions.b3"; 41 | 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @Override 47 | protected BTreeStore createBTreeStore(Configuration configuration, 48 | int branchingFactor) 49 | throws IOException { 50 | Path dataDirectory = configuration.getDataDirectory(); 51 | Path systemDirectory = dataDirectory.resolve("system"); 52 | 53 | if (!Files.exists(systemDirectory)) { 54 | Files.createDirectories(systemDirectory); 55 | } 56 | 57 | Path partitionFile = systemDirectory.resolve(PARTITIONS_FILENAME); 58 | 59 | return BTreeStore.newDiskStore(getName(), 60 | partitionFile, 61 | branchingFactor, 62 | PartitionId.getParser(), 63 | TimeSeriesPartitionMetaData.getParser()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/SlabAllocator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.io.Buffer; 19 | import io.horizondb.io.BufferAllocator; 20 | import io.horizondb.io.buffers.Buffers; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import static io.horizondb.io.files.FileUtils.printNumberOfBytes; 26 | 27 | /** 28 | * Combat heap fragmentation by ensuring that all allocations for a MemTimeSeries come from contiguous memory. Like that 29 | * large blocks of memory get freed up at the same time. 30 | * 31 | * @author Benjamin 32 | */ 33 | public final class SlabAllocator implements BufferAllocator { 34 | 35 | /** 36 | * The logger. 37 | */ 38 | private final Logger logger = LoggerFactory.getLogger(getClass()); 39 | 40 | /** 41 | * The region size. 42 | */ 43 | private final int regionSize; 44 | 45 | /** 46 | * The preallocated memory region. 47 | */ 48 | private Buffer region; 49 | 50 | /** 51 | * The number of region that have been allocated since the creation of this allocator. 52 | */ 53 | private int regionCount; 54 | 55 | /** 56 | * Creates a new SlabAllocator that preallocate large block of memory of the specified size. 57 | * 58 | * @param regionSize the size of the preallocated block of memory. 59 | */ 60 | public SlabAllocator(int regionSize) { 61 | 62 | this.regionSize = regionSize; 63 | } 64 | 65 | /** 66 | * The number of region that have been allocated. 67 | * 68 | * @return the number of region that have been allocated. 69 | */ 70 | public int getRegionCount() { 71 | return this.regionCount; 72 | } 73 | 74 | /** 75 | * {@inheritDoc} 76 | */ 77 | @Override 78 | public Buffer allocate(int size) { 79 | 80 | if (this.region == null || this.region.readableBytes() < size) { 81 | 82 | this.logger.debug("allocating a new region of size: " + printNumberOfBytes(this.regionSize)); 83 | 84 | this.region = Buffers.allocate(this.regionSize).writerIndex(this.regionSize); 85 | this.regionCount++; 86 | } 87 | 88 | return this.region.slice(size).writerIndex(0); 89 | } 90 | 91 | /** 92 | * {@inheritDoc} 93 | */ 94 | @Override 95 | public void release() { 96 | 97 | this.region = null; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.cache.AbstractCache; 20 | 21 | import com.google.common.cache.CacheBuilder; 22 | 23 | /** 24 | * Cache for time series. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | final class TimeSeriesCache extends AbstractCache { 30 | 31 | /** 32 | * Creates a TimeSeriesCache to cache the time series. 33 | * 34 | * @param configuration the database configuration. 35 | */ 36 | public TimeSeriesCache(Configuration configuration) { 37 | super(configuration); 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | @Override 44 | protected CacheBuilder newBuilder(Configuration configuration) { 45 | return CacheBuilder.newBuilder().maximumSize(configuration.getTimeSeriesCacheMaximumSize()).recordStats(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesElement.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.commitlog.ReplayPosition; 17 | import io.horizondb.model.core.DataBlock; 18 | import io.horizondb.model.core.Field; 19 | import io.horizondb.model.core.ResourceIterator; 20 | 21 | import java.io.IOException; 22 | 23 | import com.google.common.collect.RangeSet; 24 | import com.google.common.util.concurrent.ListenableFuture; 25 | 26 | /** 27 | * A time series element. A time series is divided into partition elements ({@link TimeSeriesPartition}). 28 | * Each time series partition is then divided into several elements: some in memory elements 29 | * ({@link MemTimeseries}) and a on disk element (@link {@link TimeSeriesFile}). 30 | * 31 | */ 32 | interface TimeSeriesElement { 33 | 34 | /** 35 | * Returns the commit log future returning the replay position associated to the last record of this element. 36 | * 37 | * @return the commit log future returning the replay position associated to the last record of this element. 38 | */ 39 | ListenableFuture getFuture(); 40 | 41 | /** 42 | * Returns a new iterator over all the blocks of this element. 43 | * 44 | * @param rangeSet the time range for which the blocks must be returned 45 | * @return a new iterator that can be used to read all the data of this element. 46 | * @throws IOException if an I/O problem occurs. 47 | */ 48 | ResourceIterator iterator() throws IOException; 49 | 50 | /** 51 | * Returns a new iterator over the blocks of this element containing the specified time range. 52 | * 53 | * @param rangeSet the time range for which the blocks must be returned 54 | * @return a new iterator that can be used to read the data of this element. 55 | * @throws IOException if an I/O problem occurs. 56 | */ 57 | ResourceIterator iterator(RangeSet rangeSet) throws IOException; 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.db.Component; 19 | import io.horizondb.db.HorizonDBException; 20 | import io.horizondb.model.schema.DatabaseDefinition; 21 | import io.horizondb.model.schema.TimeSeriesDefinition; 22 | 23 | import java.io.IOException; 24 | 25 | public interface TimeSeriesManager extends Component { 26 | 27 | /** 28 | * Creates the specified time series. 29 | * 30 | * @param databaseDefinition the database definition. 31 | * @param timeSeriesdefinition the time series definition. 32 | * @param throwExceptionIfExists true if an exception must be thrown if the time series already exists. 33 | * @throws IOException if an I/O problem occurs while creating the time series. 34 | * @throws HorizonDBException if a time series with the same name already exists. 35 | */ 36 | void createTimeSeries(DatabaseDefinition databaseDefinition, 37 | TimeSeriesDefinition timeSeriesdefinition, 38 | boolean throwExceptionIfExists) 39 | throws IOException, 40 | HorizonDBException; 41 | 42 | /** 43 | * Returns the time series of the specified database with the specified name if it exists. 44 | * 45 | * @param databaseDefinition the database definition. 46 | * @param seriesName the time series name. 47 | * @return the time series with the specified name if it exists. 48 | * @throws IOException if an I/O problem occurs while retrieving the time series. 49 | * @throws HorizonDBException if the time series with the specified name does not exists. 50 | */ 51 | TimeSeries getTimeSeries(DatabaseDefinition databaseDefinition, 52 | String seriesName) throws IOException, HorizonDBException; 53 | 54 | /** 55 | * Drops the specified time series. 56 | * 57 | * @param databaseDefinition the database definition. 58 | * @param seriesName the time series name. 59 | * @param throwExceptionIfDoesNotExist true if an exception must be thrown if the time series does not exists. 60 | * @throws IOException if an I/O problem occurs while dropping the time series. 61 | * @throws HorizonDBException if the time series does not exists. 62 | */ 63 | void dropTimeSeries(DatabaseDefinition databaseDefinition, 64 | String seriesName, 65 | boolean throwExceptionIfDoesNotExist) 66 | throws IOException, 67 | HorizonDBException; 68 | 69 | /** 70 | * Returns the time series with the specified ID if it exists. 71 | * 72 | * @param id the time series ID 73 | * @return the time series with the specified ID if it exists. 74 | * @throws IOException if an I/O problem occurs while retrieving the time series. 75 | * @throws HorizonDBException if the time series with the specified name does not exists. 76 | */ 77 | TimeSeries getTimeSeries(TimeSeriesId id) throws IOException, HorizonDBException; 78 | 79 | /** 80 | * Returns the TimeSeriesPartitionManager used by this TimeSeriesManager. 81 | * 82 | * @return the TimeSeriesPartitionManager used by this TimeSeriesManager. 83 | */ 84 | TimeSeriesPartitionManager getPartitionManager(); 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesPartitionListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | /** 17 | * Listener called when the memory usage or the first commit log segment containing non persisted data change. 18 | * 19 | * @author Benjamin 20 | * 21 | */ 22 | interface TimeSeriesPartitionListener { 23 | 24 | /** 25 | * Notification that the memory usage of the specified partition did change. 26 | * 27 | * @param partition the partition that has changed its memory usage 28 | * @param previousMemoryUsage the previous memory usage 29 | * @param newMemoryUsage the new memory usage 30 | */ 31 | void memoryUsageChanged(TimeSeriesPartition partition, int previousMemoryUsage, int newMemoryUsage); 32 | 33 | /** 34 | * Notification that the first segment containing non persisted data did change. 35 | * 36 | * @param partition the partition for which the first segment containing non persisted data changed 37 | * @param previousSegment the ID of the previous segment 38 | * @param newSegment the ID of the new segment 39 | */ 40 | void firstSegmentContainingNonPersistedDataChanged(TimeSeriesPartition partition, 41 | Long previousSegment, 42 | Long newSegment); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesPartitionReadCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import java.io.IOException; 19 | 20 | import io.horizondb.db.Configuration; 21 | import io.horizondb.db.HorizonDBException; 22 | import io.horizondb.db.cache.AbstractMultilevelCache; 23 | import io.horizondb.db.cache.ValueLoader; 24 | 25 | import javax.annotation.concurrent.ThreadSafe; 26 | 27 | import com.google.common.cache.CacheBuilder; 28 | 29 | /** 30 | * The time series partition read cache. 31 | * 32 | * @author Benjamin 33 | * 34 | */ 35 | @ThreadSafe 36 | final class TimeSeriesPartitionReadCache extends AbstractMultilevelCache { 37 | 38 | /** 39 | * Creates a TimeSeriesPartitionReadCache that get values from the specified cache if it does not 40 | * have them. 41 | * 42 | * @param configuration the database configuration 43 | * @param cache the second level cache 44 | */ 45 | public TimeSeriesPartitionReadCache(Configuration configuration, TimeSeriesPartitionSecondLevelCache cache) { 46 | 47 | super(configuration, cache); 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | @Override 54 | public void put(final PartitionId key, final TimeSeriesPartition value) { 55 | try { 56 | get(key, new ValueLoader() { 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | @Override 62 | public TimeSeriesPartition loadValue(PartitionId key) throws IOException, HorizonDBException { 63 | return value; 64 | } 65 | }); 66 | 67 | } catch (IOException | HorizonDBException e) { 68 | 69 | // Do nothing as no exception can occurs. 70 | } 71 | } 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @Override 77 | public TimeSeriesPartition getIfPresent(PartitionId id) { 78 | 79 | TimeSeriesPartition partition = super.getIfPresent(id); 80 | 81 | if (partition != null) { 82 | return partition; 83 | } 84 | 85 | partition = getSecondLevelCache().getIfPresent(id); 86 | 87 | if (partition != null) { 88 | put(id, partition); 89 | } 90 | return partition; 91 | } 92 | 93 | 94 | 95 | /** 96 | * {@inheritDoc} 97 | */ 98 | @Override 99 | protected CacheBuilder newBuilder(Configuration configuration) { 100 | 101 | return CacheBuilder.newBuilder() 102 | .concurrencyLevel(configuration.getCachesConcurrencyLevel()) 103 | .maximumSize(configuration.getDatabaseCacheMaximumSize()) 104 | .recordStats(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/series/TimeSeriesPartitionSecondLevelCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.db.Configuration; 19 | import io.horizondb.db.cache.AbstractCache; 20 | 21 | import javax.annotation.concurrent.ThreadSafe; 22 | 23 | import com.google.common.cache.CacheBuilder; 24 | 25 | /** 26 | * The second level cache for the time series partitions. The cache is using weak values by consequence entries will 27 | * be automatically removed on garbage collection when they are not present anymore within the read or write cache. 28 | * 29 | * @author Benjamin 30 | * 31 | */ 32 | @ThreadSafe 33 | final class TimeSeriesPartitionSecondLevelCache extends AbstractCache { 34 | 35 | /** 36 | * Creates a second level cache for the time series partition. 37 | * 38 | * @param configuration the database configuration. 39 | */ 40 | public TimeSeriesPartitionSecondLevelCache(Configuration configuration) { 41 | 42 | super(configuration); 43 | } 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | @Override 49 | protected CacheBuilder newBuilder(Configuration configuration) { 50 | 51 | return CacheBuilder.newBuilder() 52 | .concurrencyLevel(configuration.getCachesConcurrencyLevel()) 53 | .weakValues() 54 | .recordStats(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/ArrayUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util; 17 | 18 | /** 19 | * Utility methods for working with Arrays. 20 | * 21 | * @author Benjamin 22 | * 23 | */ 24 | public final class ArrayUtils extends org.apache.commons.lang.ArrayUtils { 25 | 26 | /** 27 | * Creates an arrays containing the specified elements. 28 | * 29 | * @param elements the elements of the arrays. 30 | * @return an arrays containing the specified elements. 31 | */ 32 | @SafeVarargs 33 | public static final E[] toArray(E... elements) { 34 | 35 | return elements; 36 | } 37 | 38 | /** 39 | * Must not be instantiated. 40 | */ 41 | private ArrayUtils() { 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/CountDownFuture.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.util.concurrent; 15 | 16 | import java.util.concurrent.atomic.AtomicLong; 17 | 18 | import com.google.common.util.concurrent.AbstractFuture; 19 | 20 | /** 21 | * @author Benjamin 22 | * 23 | */ 24 | public final class CountDownFuture extends AbstractFuture { 25 | 26 | private final V value; 27 | 28 | private final AtomicLong count; 29 | 30 | /** 31 | * @param value 32 | * @param latch 33 | */ 34 | public CountDownFuture(V value, int count) { 35 | this.value = value; 36 | this.count = new AtomicLong(count); 37 | } 38 | 39 | public void countDown() { 40 | if (this.count.addAndGet(-1) == 0) { 41 | set(this.value); 42 | } 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/ExecutorsUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util.concurrent; 17 | 18 | import java.util.concurrent.ExecutorService; 19 | import java.util.concurrent.ThreadFactory; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * Utility methods for {@link ExecutorService}. 27 | * 28 | * @author Benjamin 29 | * 30 | */ 31 | public final class ExecutorsUtils { 32 | 33 | /** 34 | * The class logger. 35 | */ 36 | private static final Logger LOG = LoggerFactory.getLogger(ExecutorsUtils.class); 37 | 38 | /** 39 | * Returns a thread factory used to create new threads with name with the specified prefix. 40 | * 41 | * @param prefix the prefix of the name of the threads that the factory will create. 42 | * @return a thread factory 43 | */ 44 | public static ThreadFactory namedThreadFactory(String prefix) { 45 | return new NamedThreadFactory(prefix); 46 | } 47 | 48 | /** 49 | * Shutdown the specified executor and await for its termination. If after the specified amount of time the executor 50 | * did not shutdown the system will try to stop actively the executor. 51 | * 52 | * @param executor the executor to shutdown 53 | * @param shutdownWaitingTimeInSeconds how many seconds the system will wait for the shutdown to happen before 54 | * trying to stop actively the executor. 55 | * @throws InterruptedException if interrupted while waiting for the executor to shutdown. 56 | */ 57 | public static void 58 | shutdownAndAwaitForTermination(ExecutorService executor, int shutdownWaitingTimeInSeconds) throws InterruptedException { 59 | try { 60 | executor.shutdown(); 61 | 62 | if (!executor.awaitTermination(shutdownWaitingTimeInSeconds, TimeUnit.SECONDS)) { 63 | 64 | executor.shutdownNow(); 65 | 66 | if (!executor.awaitTermination(shutdownWaitingTimeInSeconds, TimeUnit.SECONDS)) { 67 | 68 | LOG.error("The executor: {} could not be shutdown.", executor); 69 | } 70 | } 71 | 72 | } catch (InterruptedException e) { 73 | executor.shutdownNow(); 74 | throw e; 75 | } 76 | } 77 | 78 | /** 79 | * Must not be instantiated as all methods are statics. 80 | */ 81 | private ExecutorsUtils() { 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/ForwardingRunnableScheduledFuture.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.util.concurrent; 15 | 16 | import java.util.concurrent.Delayed; 17 | import java.util.concurrent.ExecutionException; 18 | import java.util.concurrent.RunnableScheduledFuture; 19 | import java.util.concurrent.TimeUnit; 20 | import java.util.concurrent.TimeoutException; 21 | 22 | /** 23 | * A RunnableScheduledFuture which forwards all its method calls to another 24 | * RunnableScheduledFuture. Subclasses should override one or more methods to modify the behavior of the 25 | * backing RunnableScheduledFuture as desired per the decorator pattern. 26 | * 27 | * @author Benjamin 28 | * 29 | */ 30 | public abstract class ForwardingRunnableScheduledFuture implements RunnableScheduledFuture { 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | @Override 36 | public void run() { 37 | delegate().run(); 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | @Override 44 | public boolean cancel(boolean mayInterruptIfRunning) { 45 | return delegate().cancel(mayInterruptIfRunning); 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | @Override 52 | public boolean isCancelled() { 53 | return delegate().isCancelled(); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public boolean isDone() { 61 | return delegate().isDone(); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public V get() throws InterruptedException, ExecutionException { 69 | return delegate().get(); 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 77 | return delegate().get(timeout, unit); 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public long getDelay(TimeUnit unit) { 85 | return delegate().getDelay(unit); 86 | } 87 | 88 | /** 89 | * {@inheritDoc} 90 | */ 91 | @Override 92 | public int compareTo(Delayed o) { 93 | return delegate().compareTo(o); 94 | } 95 | 96 | /** 97 | * {@inheritDoc} 98 | */ 99 | @Override 100 | public boolean isPeriodic() { 101 | return delegate().isPeriodic(); 102 | } 103 | 104 | protected abstract RunnableScheduledFuture delegate(); 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/FutureUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util.concurrent; 17 | 18 | import java.util.concurrent.ExecutionException; 19 | import java.util.concurrent.Future; 20 | 21 | /** 22 | * Utility methods to work with Futures. 23 | * 24 | * @author Benjamin 25 | * 26 | */ 27 | public final class FutureUtils { 28 | 29 | /** 30 | * Utility method to get the result of a future when it should not be possible to get an exception 31 | * with a get call. 32 | * 33 | * @param future the future for which the value must be returned 34 | * @return the future result 35 | */ 36 | public static V safeGet(Future future) { 37 | 38 | try { 39 | 40 | return future.get(); 41 | 42 | } catch (InterruptedException e) { 43 | 44 | Thread.currentThread().interrupt(); 45 | throw new IllegalStateException("An unexpected exception has occured", e); 46 | 47 | } catch (ExecutionException e) { 48 | throw new IllegalStateException("An unexpected exception has occured", e); 49 | } 50 | } 51 | 52 | /** 53 | * The class must not be instantiated. 54 | */ 55 | private FutureUtils() { 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/LoggingUncaughtExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util.concurrent; 17 | 18 | import java.lang.Thread.UncaughtExceptionHandler; 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | /** 24 | * UncaughtExceptionHandler that logs all the RuntimeException that it receive. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | public final class LoggingUncaughtExceptionHandler implements UncaughtExceptionHandler { 30 | 31 | /** 32 | * The class logger. 33 | */ 34 | private final Logger logger = LoggerFactory.getLogger(getClass()); 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | @Override 40 | public void uncaughtException(Thread t, Throwable e) { 41 | 42 | this.logger.error("Thread " + t.getName() + " terminated with the following Exception: ", e); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util.concurrent; 17 | 18 | import java.util.concurrent.ThreadFactory; 19 | import java.util.concurrent.atomic.AtomicInteger; 20 | 21 | import org.apache.commons.lang.Validate; 22 | 23 | /** 24 | * Thread factory that give to the thread it creates a meaningful name. 25 | * 26 | * @author Benjamin 27 | * 28 | */ 29 | public final class NamedThreadFactory implements ThreadFactory { 30 | 31 | /** 32 | * The uncaught exception handler. 33 | */ 34 | private static final LoggingUncaughtExceptionHandler exceptionHandler = new LoggingUncaughtExceptionHandler(); 35 | 36 | /** 37 | * The name separator. 38 | */ 39 | private static final char NAME_SEPARATOR = '-'; 40 | 41 | /** 42 | * The thread counter. 43 | */ 44 | private final AtomicInteger counter = new AtomicInteger(1); 45 | 46 | /** 47 | * The prefix of the name of the thread. 48 | */ 49 | private final String prefix; 50 | 51 | /** 52 | * Creates a new ThreadFactory that will used the specified prefix for the name for the threads that it 53 | * creates. 54 | * 55 | * @param prefix the prefix to use to create the thread names. 56 | */ 57 | public NamedThreadFactory(String prefix) { 58 | 59 | Validate.notEmpty(prefix, "The prefix must not be empty."); 60 | 61 | this.prefix = prefix; 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public Thread newThread(Runnable runnable) { 69 | 70 | Thread thread = new Thread(runnable, this.prefix + NAME_SEPARATOR + this.counter.getAndIncrement()); 71 | thread.setUncaughtExceptionHandler(exceptionHandler); 72 | 73 | if (thread.isDaemon()) { 74 | thread.setDaemon(false); 75 | } 76 | 77 | if (thread.getPriority() != Thread.NORM_PRIORITY) { 78 | thread.setPriority(Thread.NORM_PRIORITY); 79 | } 80 | 81 | return thread; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/horizondb/db/util/concurrent/SyncTask.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.util.concurrent; 17 | 18 | import java.util.concurrent.Callable; 19 | import java.util.concurrent.ExecutorService; 20 | 21 | /** 22 | * Callable that can be used to make sure that all the task previously submitted to a single threaded 23 | * {@link ExecutorService} have been executed. 24 | * 25 | * @author Benjamin 26 | * 27 | */ 28 | public final class SyncTask implements Callable { 29 | 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | @Override 34 | public Boolean call() { 35 | return Boolean.TRUE; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scripts/horizondb.bat: -------------------------------------------------------------------------------- 1 | @REM Copyright 2014 Benjamin Lerer 2 | @REM 3 | @REM Licensed under the Apache License, Version 2.0 (the "License"); 4 | @REM you may not use this file except in compliance with the License. 5 | @REM You may obtain a copy of the License at 6 | @REM 7 | @REM http://www.apache.org/licenses/LICENSE-2.0 8 | @REM 9 | @REM Unless required by applicable law or agreed to in writing, software 10 | @REM distributed under the License is distributed on an "AS IS" BASIS, 11 | @REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | @REM See the License for the specific language governing permissions and 13 | @REM limitations under the License. 14 | @REM 15 | 16 | @echo off 17 | if "%OS%" == "Windows_NT" SETLOCAL 18 | 19 | pushd %~dp0.. 20 | if NOT DEFINED HORIZONDB_HOME set HORIZONDB_HOME=%CD% 21 | popd 22 | 23 | if NOT DEFINED HORIZONDB_MAIN set HORIZONDB_MAIN=io.horizondb.db.HorizonDbDaemon 24 | if NOT DEFINED JAVA_HOME goto :err 25 | 26 | set JAVA_OPTS=-Xms1G^ 27 | -Xmx1G^ 28 | -XX:+HeapDumpOnOutOfMemoryError^ 29 | -XX:+UseParNewGC^ 30 | -XX:+UseConcMarkSweepGC^ 31 | -XX:+CMSParallelRemarkEnabled^ 32 | -XX:SurvivorRatio=8^ 33 | -XX:MaxTenuringThreshold=1^ 34 | -XX:CMSInitiatingOccupancyFraction=75^ 35 | -XX:+UseCMSInitiatingOccupancyOnly 36 | 37 | set CLASSPATH="%HORIZONDB_HOME%\conf" 38 | 39 | for %%i in ("%HORIZONDB_HOME%\lib\*.jar") do call :append "%%i" 40 | goto :runDaemon 41 | 42 | :append 43 | set CLASSPATH=%CLASSPATH%;%1 44 | goto :eof 45 | 46 | :runDaemon 47 | echo Starting HorizonDB 48 | "%JAVA_HOME%\bin\java" %JAVA_OPTS% -cp %CLASSPATH% "%HORIZONDB_MAIN%" 49 | goto finally 50 | 51 | :err 52 | echo JAVA_HOME environment variable must be set 53 | pause 54 | 55 | :finally 56 | 57 | ENDLOCAL -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/PropertiesFileConfigurationLoaderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db; 17 | 18 | import java.io.IOException; 19 | 20 | import org.junit.Test; 21 | 22 | /** 23 | * @author Benjamin 24 | * 25 | */ 26 | public class PropertiesFileConfigurationLoaderTest { 27 | 28 | @Test 29 | public void testLoadConfigurationFromClassPath() throws IOException, HorizonDBException { 30 | 31 | PropertiesFileConfigurationLoader loader = new PropertiesFileConfigurationLoader(); 32 | 33 | loader.loadConfigurationFromClasspath("horizondb-config.properties"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/btree/IntegerAndStringNodeReader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import io.horizondb.io.ByteReader; 19 | import io.horizondb.io.encoding.VarInts; 20 | import io.horizondb.io.files.SeekableFileDataInput; 21 | 22 | import java.io.IOException; 23 | 24 | import static io.horizondb.io.encoding.VarInts.readInt; 25 | 26 | /** 27 | * @author Benjamin 28 | * 29 | */ 30 | public class IntegerAndStringNodeReader extends AbstractNodeReader { 31 | 32 | public static final NodeReaderFactory FACTORY = new NodeReaderFactory() { 33 | 34 | @Override 35 | public NodeReader newReader(SeekableFileDataInput input) throws IOException { 36 | return new IntegerAndStringNodeReader(input); 37 | } 38 | 39 | }; 40 | 41 | /** 42 | * @param input 43 | * @throws IOException 44 | */ 45 | public IntegerAndStringNodeReader(SeekableFileDataInput input) throws IOException { 46 | super(input); 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | @Override 53 | protected Integer readKey(ByteReader reader) throws IOException { 54 | return Integer.valueOf(readInt(reader)); 55 | } 56 | 57 | /** 58 | * {@inheritDoc} 59 | * 60 | * @throws IOException 61 | */ 62 | @Override 63 | protected String readValue(ByteReader reader) throws IOException { 64 | return VarInts.readString(reader); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/btree/IntegerAndStringNodeWriter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.btree; 17 | 18 | import io.horizondb.db.btree.AbstractNodeWriter; 19 | import io.horizondb.db.btree.NodeWriter; 20 | import io.horizondb.db.btree.NodeWriterFactory; 21 | import io.horizondb.io.ByteWriter; 22 | import io.horizondb.io.files.FileDataOutput; 23 | 24 | import java.io.IOException; 25 | 26 | import static io.horizondb.io.encoding.VarInts.computeIntSize; 27 | import static io.horizondb.io.encoding.VarInts.computeStringSize; 28 | import static io.horizondb.io.encoding.VarInts.writeInt; 29 | import static io.horizondb.io.encoding.VarInts.writeString; 30 | 31 | /** 32 | * @author Benjamin 33 | * 34 | */ 35 | public class IntegerAndStringNodeWriter extends AbstractNodeWriter { 36 | 37 | public static final NodeWriterFactory FACTORY = new NodeWriterFactory() { 38 | 39 | @Override 40 | public NodeWriter newWriter(FileDataOutput output) throws IOException { 41 | return new IntegerAndStringNodeWriter(output); 42 | } 43 | }; 44 | 45 | public IntegerAndStringNodeWriter(FileDataOutput output) throws IOException { 46 | 47 | super(output); 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | @Override 54 | protected void writeValue(ByteWriter writer, String value) throws IOException { 55 | writeString(writer, value); 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | @Override 62 | protected int computeKeySize(Integer key) { 63 | 64 | return computeIntSize(key.intValue()); 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | @Override 71 | protected void writeKey(ByteWriter writer, Integer key) throws IOException { 72 | 73 | writeInt(writer, key.intValue()); 74 | } 75 | 76 | /** 77 | * {@inheritDoc} 78 | */ 79 | @Override 80 | protected int computeValueSize(String value) { 81 | 82 | return computeStringSize(value); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/commitlog/ReplayPositionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.commitlog; 17 | 18 | import org.junit.Test; 19 | 20 | import static org.junit.Assert.*; 21 | 22 | /** 23 | * @author Benjamin 24 | * 25 | */ 26 | public class ReplayPositionTest { 27 | 28 | @Test 29 | public void testIsAfter() { 30 | 31 | ReplayPosition pos = new ReplayPosition(0, 1); 32 | ReplayPosition pos2 = new ReplayPosition(0, 2); 33 | 34 | assertFalse(pos.isAfter(pos2)); 35 | assertTrue(pos2.isAfter(pos)); 36 | 37 | pos2 = new ReplayPosition(1, 1); 38 | 39 | assertFalse(pos.isAfter(pos2)); 40 | assertTrue(pos2.isAfter(pos)); 41 | 42 | pos2 = new ReplayPosition(0, 1); 43 | 44 | assertFalse(pos.isAfter(pos2)); 45 | assertFalse(pos2.isAfter(pos)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/series/FileMetaDataTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.io.Buffer; 19 | import io.horizondb.io.buffers.Buffers; 20 | import io.horizondb.io.checksum.ChecksumMismatchException; 21 | import io.horizondb.model.core.Field; 22 | 23 | import java.io.IOException; 24 | 25 | import org.junit.Test; 26 | 27 | import com.google.common.collect.Range; 28 | 29 | import static io.horizondb.model.schema.FieldType.MILLISECONDS_TIMESTAMP; 30 | import static org.junit.Assert.assertEquals; 31 | import static org.junit.Assert.assertTrue; 32 | import static org.junit.Assert.fail; 33 | 34 | /** 35 | * @author Benjamin 36 | * 37 | */ 38 | public class FileMetaDataTest { 39 | 40 | @Test 41 | public void testParseFrom() throws IOException { 42 | 43 | Range range = MILLISECONDS_TIMESTAMP.range("'2013-11-26'", "'2013-11-27'"); 44 | 45 | FileMetaData metadata = new FileMetaData("test", "test", range); 46 | 47 | Buffer buffer = Buffers.allocate(metadata.computeSerializedSize()); 48 | metadata.writeTo(buffer); 49 | 50 | FileMetaData result = FileMetaData.parseFrom(buffer); 51 | 52 | assertEquals(metadata, result); 53 | } 54 | 55 | @Test 56 | public void testParseFromWithInvalidCrc() throws IOException { 57 | 58 | Range range = MILLISECONDS_TIMESTAMP.range("'2013-11-26'", "'2013-11-27'"); 59 | 60 | FileMetaData metadata = new FileMetaData("test", "test", range); 61 | 62 | Buffer buffer = Buffers.allocate(metadata.computeSerializedSize()); 63 | metadata.writeTo(buffer); 64 | 65 | buffer.writerIndex(buffer.writerIndex() - 8).writeLong(1); // Modify the 66 | // CRC 67 | 68 | try { 69 | FileMetaData.parseFrom(buffer); 70 | fail(); 71 | } catch (ChecksumMismatchException e) { 72 | assertTrue(true); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/series/MapKeyValueIteratorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.series; 15 | 16 | import io.horizondb.db.series.MapKeyValueIterator; 17 | 18 | import java.util.Collections; 19 | import java.util.Map; 20 | 21 | import org.junit.Test; 22 | 23 | import com.google.common.collect.ImmutableMap; 24 | 25 | import static org.junit.Assert.assertEquals; 26 | import static org.junit.Assert.assertFalse; 27 | import static org.junit.Assert.assertTrue; 28 | 29 | /** 30 | * @author Benjamin 31 | * 32 | */ 33 | public class MapKeyValueIteratorTest { 34 | 35 | @Test 36 | public void testEmptyMap() { 37 | 38 | MapKeyValueIterator iterator = new MapKeyValueIterator<>(Collections.emptyMap()); 39 | assertFalse(iterator.next()); 40 | } 41 | 42 | @Test 43 | public void testWithOneMapEntry() { 44 | 45 | Map map = ImmutableMap.of("A", "1"); 46 | 47 | MapKeyValueIterator iterator = new MapKeyValueIterator<>(map); 48 | assertTrue(iterator.next()); 49 | assertEquals("A", iterator.getKey()); 50 | assertEquals("1", iterator.getValue()); 51 | assertFalse(iterator.next()); 52 | } 53 | 54 | @Test 55 | public void testWithTwoMapEntry() { 56 | 57 | Map map = ImmutableMap.of("A", "1", "B", "2"); 58 | 59 | MapKeyValueIterator iterator = new MapKeyValueIterator<>(map); 60 | assertTrue(iterator.next()); 61 | assertEquals("A", iterator.getKey()); 62 | assertEquals("1", iterator.getValue()); 63 | assertTrue(iterator.next()); 64 | assertEquals("B", iterator.getKey()); 65 | assertEquals("2", iterator.getValue()); 66 | assertFalse(iterator.next()); 67 | } 68 | 69 | @Test 70 | public void testWithTwoMapEntriesInWrongOrder() { 71 | 72 | Map map = ImmutableMap.of("B", "2", "A", "1"); 73 | 74 | MapKeyValueIterator iterator = new MapKeyValueIterator<>(map); 75 | assertTrue(iterator.next()); 76 | assertEquals("A", iterator.getKey()); 77 | assertEquals("1", iterator.getValue()); 78 | assertTrue(iterator.next()); 79 | assertEquals("B", iterator.getKey()); 80 | assertEquals("2", iterator.getValue()); 81 | assertFalse(iterator.next()); 82 | } 83 | 84 | @Test 85 | public void testWithMultipleMapEntriesInWrongOrder() { 86 | 87 | Map map = ImmutableMap.of("B", "2", "C", "3", "A", "1", "D", "4"); 88 | 89 | MapKeyValueIterator iterator = new MapKeyValueIterator<>(map); 90 | assertTrue(iterator.next()); 91 | assertEquals("A", iterator.getKey()); 92 | assertEquals("1", iterator.getValue()); 93 | assertTrue(iterator.next()); 94 | assertEquals("B", iterator.getKey()); 95 | assertEquals("2", iterator.getValue()); 96 | assertTrue(iterator.next()); 97 | assertEquals("C", iterator.getKey()); 98 | assertEquals("3", iterator.getValue()); 99 | assertTrue(iterator.next()); 100 | assertEquals("D", iterator.getKey()); 101 | assertEquals("4", iterator.getValue()); 102 | assertFalse(iterator.next()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/series/SlabAllocatorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Benjamin Lerer 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.horizondb.db.series; 17 | 18 | import io.horizondb.io.Buffer; 19 | import io.horizondb.io.BufferAllocator; 20 | 21 | import org.junit.Test; 22 | 23 | import static io.horizondb.io.files.FileUtils.ONE_KB; 24 | import static org.junit.Assert.assertEquals; 25 | import static org.junit.Assert.assertFalse; 26 | 27 | /** 28 | * @author Benjamin 29 | * 30 | */ 31 | public class SlabAllocatorTest { 32 | 33 | @Test 34 | public void testAllocate() { 35 | 36 | SlabAllocator allocator = new SlabAllocator(60 * ONE_KB); 37 | 38 | Buffer firstBuffer = allocator.allocate(20 * ONE_KB); 39 | byte[] firstArray = firstBuffer.array(); 40 | assertEquals(0, firstBuffer.arrayOffset()); 41 | assertEquals(1, allocator.getRegionCount()); 42 | 43 | Buffer secondBuffer = allocator.allocate(30 * ONE_KB); 44 | byte[] secondArray = secondBuffer.array(); 45 | 46 | assertEquals(firstArray, secondArray); 47 | assertEquals(20 * ONE_KB, secondBuffer.arrayOffset()); 48 | assertEquals(1, allocator.getRegionCount()); 49 | 50 | Buffer thirdBuffer = allocator.allocate(30 * ONE_KB); 51 | byte[] thirdArray = thirdBuffer.array(); 52 | 53 | assertFalse(secondArray.equals(thirdArray)); 54 | assertEquals(2, allocator.getRegionCount()); 55 | } 56 | 57 | @Test 58 | public void testAllocateWithWrite() { 59 | 60 | BufferAllocator allocator = new SlabAllocator(60 * ONE_KB); 61 | 62 | Buffer buffer = allocator.allocate(10); 63 | 64 | buffer.writeByte(1); 65 | } 66 | 67 | @Test 68 | public void testRelease() { 69 | 70 | SlabAllocator allocator = new SlabAllocator(60 * ONE_KB); 71 | 72 | Buffer firstBuffer = allocator.allocate(20 * ONE_KB); 73 | byte[] firstArray = firstBuffer.array(); 74 | assertEquals(1, allocator.getRegionCount()); 75 | 76 | allocator.release(); 77 | 78 | Buffer secondBuffer = allocator.allocate(30 * ONE_KB); 79 | byte[] secondArray = secondBuffer.array(); 80 | assertEquals(2, allocator.getRegionCount()); 81 | 82 | assertFalse(firstArray.equals(secondArray)); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/io/horizondb/db/util/concurrent/CountDownFutureTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package io.horizondb.db.util.concurrent; 15 | 16 | import java.util.concurrent.Callable; 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.concurrent.Executors; 19 | import java.util.concurrent.Future; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import org.junit.Test; 23 | 24 | import static org.junit.Assert.assertFalse; 25 | 26 | /** 27 | * @author Benjamin 28 | * 29 | */ 30 | public class CountDownFutureTest { 31 | 32 | @Test 33 | public void testCountDown() throws Exception { 34 | 35 | final CountDownFuture future = new CountDownFuture(Boolean.TRUE, 2); 36 | 37 | Callable callable = new Callable() { 38 | 39 | @Override 40 | public Boolean call() throws Exception { 41 | 42 | return future.get(); 43 | } 44 | }; 45 | 46 | ExecutorService executor = Executors.newSingleThreadExecutor(); 47 | 48 | try { 49 | Future completionMonitor = executor.submit(callable); 50 | 51 | assertFalse(completionMonitor.isDone()); 52 | future.countDown(); 53 | Thread.sleep(100); 54 | assertFalse(completionMonitor.isDone()); 55 | future.countDown(); 56 | future.get(100, TimeUnit.MILLISECONDS); 57 | } finally { 58 | executor.shutdown(); 59 | } 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/test/resources/horizondb-config.properties: -------------------------------------------------------------------------------- 1 | # the port on which listen the server is listening. 2 | port = 8553 3 | 4 | # the maximum size in KB for the memTimeSeries 5 | memTimeSeriesSizeInKB = 128 6 | 7 | # the data directory 8 | dataDirectory = /var/lib/horizondb/data; 9 | 10 | # the commit log directory 11 | commitLogDirectory = /var/lib/horizondb/commitlog; 12 | 13 | # the maximum number of commit log segments. 14 | maximumNumberOfCommitLogSegments = 8 15 | 16 | # the commit log segment size in MB 17 | commitLogSegmentSizeInMB = 1024 18 | 19 | # the period of time in milliseconds at which the commit log will flush data to the disk 20 | commitLogFlushPeriodInMillis = 100 21 | 22 | # the maximum number of entries in the database cache 23 | databaseCacheMaximumSize = 20 24 | 25 | # the maximum number of entries in the time series cache 26 | timeSeriesCacheMaximumSize = 200 27 | 28 | # the maximum amount of memory in MB that is allowed to be used by the MemTimeSeries 29 | maximumMemoryUsageByMemTimeSeriesInMB = 512 30 | 31 | # The time in second after which a MemTimeSeries must be flushed to the disk 32 | memTimeSeriesIdleTimeInSecond = 7200 --------------------------------------------------------------------------------