|
|
|
@ -31,16 +31,17 @@ import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageTransaction |
|
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.Optional; |
|
|
|
|
import java.util.Set; |
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean; |
|
|
|
|
import java.util.concurrent.atomic.AtomicReference; |
|
|
|
|
import java.util.function.Predicate; |
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
import java.util.stream.Stream; |
|
|
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableMap; |
|
|
|
|
import org.apache.tuweni.bytes.Bytes; |
|
|
|
|
import org.rocksdb.BlockBasedTableConfig; |
|
|
|
|
import org.rocksdb.ColumnFamilyDescriptor; |
|
|
|
@ -62,19 +63,19 @@ import org.slf4j.LoggerFactory; |
|
|
|
|
public class RocksDBColumnarKeyValueStorage |
|
|
|
|
implements SegmentedKeyValueStorage<ColumnFamilyHandle> { |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
RocksDbUtil.loadNativeLibrary(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(RocksDBColumnarKeyValueStorage.class); |
|
|
|
|
private static final String DEFAULT_COLUMN = "default"; |
|
|
|
|
private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
RocksDbUtil.loadNativeLibrary(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final DBOptions options; |
|
|
|
|
private final TransactionDBOptions txOptions; |
|
|
|
|
private final TransactionDB db; |
|
|
|
|
private final AtomicBoolean closed = new AtomicBoolean(false); |
|
|
|
|
private final Map<String, ColumnFamilyHandle> columnHandlesByName; |
|
|
|
|
private final Map<String, AtomicReference<ColumnFamilyHandle>> columnHandlesByName; |
|
|
|
|
private final RocksDBMetrics metrics; |
|
|
|
|
private final WriteOptions tryDeleteOptions = new WriteOptions().setNoSlowdown(true); |
|
|
|
|
|
|
|
|
@ -127,14 +128,17 @@ public class RocksDBColumnarKeyValueStorage |
|
|
|
|
Collectors.toMap( |
|
|
|
|
segment -> Bytes.wrap(segment.getId()), SegmentIdentifier::getName)); |
|
|
|
|
|
|
|
|
|
columnHandlesByName = new HashMap<>(); |
|
|
|
|
final ImmutableMap.Builder<String, AtomicReference<ColumnFamilyHandle>> builder = |
|
|
|
|
ImmutableMap.builder(); |
|
|
|
|
|
|
|
|
|
for (ColumnFamilyHandle columnHandle : columnHandles) { |
|
|
|
|
final String segmentName = |
|
|
|
|
requireNonNullElse( |
|
|
|
|
segmentsById.get(Bytes.wrap(columnHandle.getName())), DEFAULT_COLUMN); |
|
|
|
|
columnHandlesByName.put(segmentName, columnHandle); |
|
|
|
|
builder.put(segmentName, new AtomicReference<>(columnHandle)); |
|
|
|
|
} |
|
|
|
|
columnHandlesByName = builder.build(); |
|
|
|
|
|
|
|
|
|
} catch (final RocksDBException e) { |
|
|
|
|
throw new StorageException(e); |
|
|
|
|
} |
|
|
|
@ -146,7 +150,8 @@ public class RocksDBColumnarKeyValueStorage |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ColumnFamilyHandle getSegmentIdentifierByName(final SegmentIdentifier segment) { |
|
|
|
|
public AtomicReference<ColumnFamilyHandle> getSegmentIdentifierByName( |
|
|
|
|
final SegmentIdentifier segment) { |
|
|
|
|
return columnHandlesByName.get(segment.getName()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -198,30 +203,27 @@ public class RocksDBColumnarKeyValueStorage |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ColumnFamilyHandle clear(final ColumnFamilyHandle segmentHandle) { |
|
|
|
|
try { |
|
|
|
|
|
|
|
|
|
var entry = |
|
|
|
|
columnHandlesByName.entrySet().stream() |
|
|
|
|
.filter(e -> e.getValue().equals(segmentHandle)) |
|
|
|
|
.findAny(); |
|
|
|
|
|
|
|
|
|
if (entry.isPresent()) { |
|
|
|
|
String segmentName = entry.get().getKey(); |
|
|
|
|
ColumnFamilyDescriptor descriptor = |
|
|
|
|
new ColumnFamilyDescriptor( |
|
|
|
|
segmentHandle.getName(), segmentHandle.getDescriptor().getOptions()); |
|
|
|
|
db.dropColumnFamily(segmentHandle); |
|
|
|
|
segmentHandle.close(); |
|
|
|
|
ColumnFamilyHandle newHandle = db.createColumnFamily(descriptor); |
|
|
|
|
columnHandlesByName.put(segmentName, newHandle); |
|
|
|
|
return newHandle; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return segmentHandle; |
|
|
|
|
|
|
|
|
|
} catch (final RocksDBException e) { |
|
|
|
|
throw new StorageException(e); |
|
|
|
|
public void clear(final ColumnFamilyHandle segmentHandle) { |
|
|
|
|
|
|
|
|
|
var entry = |
|
|
|
|
columnHandlesByName.values().stream().filter(e -> e.get().equals(segmentHandle)).findAny(); |
|
|
|
|
|
|
|
|
|
if (entry.isPresent()) { |
|
|
|
|
AtomicReference<ColumnFamilyHandle> segmentHandleRef = entry.get(); |
|
|
|
|
segmentHandleRef.getAndUpdate( |
|
|
|
|
oldHandle -> { |
|
|
|
|
try { |
|
|
|
|
ColumnFamilyDescriptor descriptor = |
|
|
|
|
new ColumnFamilyDescriptor( |
|
|
|
|
segmentHandle.getName(), segmentHandle.getDescriptor().getOptions()); |
|
|
|
|
db.dropColumnFamily(oldHandle); |
|
|
|
|
ColumnFamilyHandle newHandle = db.createColumnFamily(descriptor); |
|
|
|
|
segmentHandle.close(); |
|
|
|
|
return newHandle; |
|
|
|
|
} catch (final RocksDBException e) { |
|
|
|
|
throw new StorageException(e); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,7 +233,9 @@ public class RocksDBColumnarKeyValueStorage |
|
|
|
|
txOptions.close(); |
|
|
|
|
options.close(); |
|
|
|
|
tryDeleteOptions.close(); |
|
|
|
|
columnHandlesByName.values().forEach(ColumnFamilyHandle::close); |
|
|
|
|
columnHandlesByName.values().stream() |
|
|
|
|
.map(AtomicReference::get) |
|
|
|
|
.forEach(ColumnFamilyHandle::close); |
|
|
|
|
db.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|