├── .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