mirror of https://github.com/hyperledger/besu
Rocksdb plugin to support OptimisticTransactionDb and TransactionDb (#5328)
* Refactor to make RocksDBColumnarKeyValueStorage abstract and extend it to optimistic and pessimistic. Atm Forest has a concurrency level that does not cope well with the OptimisticTransactionDB and RocksDB ends up raising a lot of Busy when committing RocksDBTransactions. A TransactionDB will do conflict checking for all write operations (Put, Delete and Merge), including writes performed outside a Transaction according to RocksDB. This does impact the times we see when syncing so likely not the final solution for Forest. Bonsai should continue using OptimisticTransactionDB. Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> --------- Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>pull/4427/head
parent
78f8efff7a
commit
d54a1bf27a
@ -0,0 +1,99 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; |
||||
|
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
import org.hyperledger.besu.plugin.services.exception.StorageException; |
||||
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; |
||||
import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionTransitionValidatorDecorator; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.rocksdb.OptimisticTransactionDB; |
||||
import org.rocksdb.RocksDB; |
||||
import org.rocksdb.RocksDBException; |
||||
import org.rocksdb.WriteOptions; |
||||
|
||||
/** Optimistic RocksDB Columnar key value storage */ |
||||
public class OptimisticRocksDBColumnarKeyValueStorage extends RocksDBColumnarKeyValueStorage { |
||||
private final OptimisticTransactionDB db; |
||||
|
||||
/** |
||||
* Instantiates a new Rocks db columnar key value optimistic storage. |
||||
* |
||||
* @param configuration the configuration |
||||
* @param segments the segments |
||||
* @param ignorableSegments the ignorable segments |
||||
* @param metricsSystem the metrics system |
||||
* @param rocksDBMetricsFactory the rocks db metrics factory |
||||
* @throws StorageException the storage exception |
||||
*/ |
||||
public OptimisticRocksDBColumnarKeyValueStorage( |
||||
final RocksDBConfiguration configuration, |
||||
final List<SegmentIdentifier> segments, |
||||
final List<SegmentIdentifier> ignorableSegments, |
||||
final MetricsSystem metricsSystem, |
||||
final RocksDBMetricsFactory rocksDBMetricsFactory) |
||||
throws StorageException { |
||||
super(configuration, segments, ignorableSegments, metricsSystem, rocksDBMetricsFactory); |
||||
try { |
||||
|
||||
db = |
||||
OptimisticTransactionDB.open( |
||||
options, configuration.getDatabaseDir().toString(), columnDescriptors, columnHandles); |
||||
initMetrics(); |
||||
initColumnHandler(); |
||||
|
||||
} catch (final RocksDBException e) { |
||||
throw new StorageException(e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
RocksDB getDB() { |
||||
return db; |
||||
} |
||||
|
||||
/** |
||||
* Start a transaction |
||||
* |
||||
* @return the new transaction started |
||||
* @throws StorageException the storage exception |
||||
*/ |
||||
@Override |
||||
public Transaction<RocksDbSegmentIdentifier> startTransaction() throws StorageException { |
||||
throwIfClosed(); |
||||
final WriteOptions writeOptions = new WriteOptions(); |
||||
writeOptions.setIgnoreMissingColumnFamilies(true); |
||||
return new SegmentedKeyValueStorageTransactionTransitionValidatorDecorator<>( |
||||
new RocksDbTransaction(db.beginTransaction(writeOptions), writeOptions)); |
||||
} |
||||
|
||||
/** |
||||
* Take snapshot RocksDb columnar key value snapshot. |
||||
* |
||||
* @param segment the segment |
||||
* @return the RocksDb columnar key value snapshot |
||||
* @throws StorageException the storage exception |
||||
*/ |
||||
public RocksDBColumnarKeyValueSnapshot takeSnapshot(final RocksDbSegmentIdentifier segment) |
||||
throws StorageException { |
||||
throwIfClosed(); |
||||
return new RocksDBColumnarKeyValueSnapshot(db, segment, metrics); |
||||
} |
||||
} |
@ -0,0 +1,91 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; |
||||
|
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
import org.hyperledger.besu.plugin.services.exception.StorageException; |
||||
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfiguration; |
||||
import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransactionTransitionValidatorDecorator; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.rocksdb.RocksDB; |
||||
import org.rocksdb.RocksDBException; |
||||
import org.rocksdb.TransactionDB; |
||||
import org.rocksdb.WriteOptions; |
||||
|
||||
/** TransactionDB RocksDB Columnar key value storage */ |
||||
public class TransactionDBRocksDBColumnarKeyValueStorage extends RocksDBColumnarKeyValueStorage { |
||||
|
||||
private final TransactionDB db; |
||||
|
||||
/** |
||||
* The constructor of TransactionDBRocksDBColumnarKeyValueStorage |
||||
* |
||||
* @param configuration the RocksDB configuration |
||||
* @param segments the segments |
||||
* @param ignorableSegments the ignorable segments |
||||
* @param metricsSystem the metrics system |
||||
* @param rocksDBMetricsFactory the rocksdb metrics factory |
||||
* @throws StorageException the storage exception |
||||
*/ |
||||
public TransactionDBRocksDBColumnarKeyValueStorage( |
||||
final RocksDBConfiguration configuration, |
||||
final List<SegmentIdentifier> segments, |
||||
final List<SegmentIdentifier> ignorableSegments, |
||||
final MetricsSystem metricsSystem, |
||||
final RocksDBMetricsFactory rocksDBMetricsFactory) |
||||
throws StorageException { |
||||
super(configuration, segments, ignorableSegments, metricsSystem, rocksDBMetricsFactory); |
||||
try { |
||||
|
||||
db = |
||||
TransactionDB.open( |
||||
options, |
||||
txOptions, |
||||
configuration.getDatabaseDir().toString(), |
||||
columnDescriptors, |
||||
columnHandles); |
||||
initMetrics(); |
||||
initColumnHandler(); |
||||
|
||||
} catch (final RocksDBException e) { |
||||
throw new StorageException(e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
RocksDB getDB() { |
||||
return db; |
||||
} |
||||
|
||||
/** |
||||
* Start a transaction |
||||
* |
||||
* @return the new transaction started |
||||
* @throws StorageException the storage exception |
||||
*/ |
||||
@Override |
||||
public Transaction<RocksDbSegmentIdentifier> startTransaction() throws StorageException { |
||||
throwIfClosed(); |
||||
final WriteOptions writeOptions = new WriteOptions(); |
||||
writeOptions.setIgnoreMissingColumnFamilies(true); |
||||
return new SegmentedKeyValueStorageTransactionTransitionValidatorDecorator<>( |
||||
new RocksDbTransaction(db.beginTransaction(writeOptions), writeOptions)); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; |
||||
|
||||
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; |
||||
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; |
||||
import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; |
||||
|
||||
import java.nio.file.Path; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
public class OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest |
||||
extends RocksDBColumnarKeyValueStorageTest { |
||||
|
||||
@Override |
||||
protected SegmentedKeyValueStorage<RocksDbSegmentIdentifier> createSegmentedStore() |
||||
throws Exception { |
||||
return new OptimisticRocksDBColumnarKeyValueStorage( |
||||
new RocksDBConfigurationBuilder().databaseDir(folder.newFolder().toPath()).build(), |
||||
Arrays.asList(TestSegment.FOO, TestSegment.BAR), |
||||
List.of(), |
||||
new NoOpMetricsSystem(), |
||||
RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); |
||||
} |
||||
|
||||
@Override |
||||
protected SegmentedKeyValueStorage<RocksDbSegmentIdentifier> createSegmentedStore( |
||||
final Path path, |
||||
final List<SegmentIdentifier> segments, |
||||
final List<SegmentIdentifier> ignorableSegments) { |
||||
return new OptimisticRocksDBColumnarKeyValueStorage( |
||||
new RocksDBConfigurationBuilder().databaseDir(path).build(), |
||||
segments, |
||||
ignorableSegments, |
||||
new NoOpMetricsSystem(), |
||||
RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.plugin.services.storage.rocksdb.segmented; |
||||
|
||||
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; |
||||
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBConfigurationBuilder; |
||||
import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorage; |
||||
|
||||
import java.nio.file.Path; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
public class TransactionDBRocksDBColumnarKeyValueStorageTest |
||||
extends RocksDBColumnarKeyValueStorageTest { |
||||
|
||||
@Override |
||||
protected SegmentedKeyValueStorage<RocksDbSegmentIdentifier> createSegmentedStore() |
||||
throws Exception { |
||||
return new TransactionDBRocksDBColumnarKeyValueStorage( |
||||
new RocksDBConfigurationBuilder().databaseDir(folder.newFolder().toPath()).build(), |
||||
Arrays.asList(TestSegment.FOO, TestSegment.BAR), |
||||
List.of(), |
||||
new NoOpMetricsSystem(), |
||||
RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); |
||||
} |
||||
|
||||
@Override |
||||
protected SegmentedKeyValueStorage<RocksDbSegmentIdentifier> createSegmentedStore( |
||||
final Path path, |
||||
final List<SegmentIdentifier> segments, |
||||
final List<SegmentIdentifier> ignorableSegments) { |
||||
return new TransactionDBRocksDBColumnarKeyValueStorage( |
||||
new RocksDBConfigurationBuilder().databaseDir(path).build(), |
||||
segments, |
||||
ignorableSegments, |
||||
new NoOpMetricsSystem(), |
||||
RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); |
||||
} |
||||
} |
@ -0,0 +1,67 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.services.kvstore; |
||||
|
||||
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; |
||||
import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; |
||||
import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; |
||||
|
||||
import java.util.function.Supplier; |
||||
|
||||
/** |
||||
* The type Segmented key value storage adapter. |
||||
* |
||||
* @param <S> the type parameter |
||||
*/ |
||||
public class SnappableSegmentedKeyValueStorageAdapter<S> extends SegmentedKeyValueStorageAdapter<S> |
||||
implements SnappableKeyValueStorage { |
||||
private final Supplier<SnappedKeyValueStorage> snapshotSupplier; |
||||
|
||||
/** |
||||
* Instantiates a new Segmented key value storage adapter. |
||||
* |
||||
* @param segment the segment |
||||
* @param storage the storage |
||||
*/ |
||||
public SnappableSegmentedKeyValueStorageAdapter( |
||||
final SegmentIdentifier segment, final SegmentedKeyValueStorage<S> storage) { |
||||
this( |
||||
segment, |
||||
storage, |
||||
() -> { |
||||
throw new UnsupportedOperationException("Snapshot not supported"); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Instantiates a new Segmented key value storage adapter. |
||||
* |
||||
* @param segment the segment |
||||
* @param storage the storage |
||||
* @param snapshotSupplier the snapshot supplier |
||||
*/ |
||||
public SnappableSegmentedKeyValueStorageAdapter( |
||||
final SegmentIdentifier segment, |
||||
final SegmentedKeyValueStorage<S> storage, |
||||
final Supplier<SnappedKeyValueStorage> snapshotSupplier) { |
||||
super(segment, storage); |
||||
this.snapshotSupplier = snapshotSupplier; |
||||
} |
||||
|
||||
@Override |
||||
public SnappedKeyValueStorage takeSnapshot() { |
||||
return snapshotSupplier.get(); |
||||
} |
||||
} |
Loading…
Reference in new issue