use of org.neo4j.storageengine.api.LogVersionRepository in project neo4j by neo4j.
the class TransactionLogFileRotateAndReadRaceIT method shouldNotSeeEmptyLogFileWhenReadingTransactionStream.
@Test
void shouldNotSeeEmptyLogFileWhenReadingTransactionStream() throws Exception {
// GIVEN
LogVersionRepository logVersionRepository = new SimpleLogVersionRepository();
Config cfg = Config.newBuilder().set(GraphDatabaseSettings.neo4j_home, databaseLayout.getNeo4jLayout().homeDirectory()).set(GraphDatabaseSettings.preallocate_logical_logs, false).set(GraphDatabaseSettings.logical_log_rotation_threshold, ByteUnit.kibiBytes(128)).build();
LogFiles logFiles = LogFilesBuilder.builder(databaseLayout, fs).withLogVersionRepository(logVersionRepository).withTransactionIdStore(new SimpleTransactionIdStore()).withLogEntryReader(new VersionAwareLogEntryReader(new TestCommandReaderFactory())).withConfig(cfg).withStoreId(StoreId.UNKNOWN).build();
life.add(logFiles);
LogFile logFile = logFiles.getLogFile();
var writer = logFile.getTransactionLogWriter();
LogPositionMarker startPosition = new LogPositionMarker();
writer.getCurrentPosition(startPosition);
// WHEN
AtomicBoolean end = new AtomicBoolean();
byte[] dataChunk = new byte[100];
// one thread constantly writing to and rotating the channel
CountDownLatch startSignal = new CountDownLatch(1);
Future<Void> writeFuture = t2.execute(() -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
startSignal.countDown();
int rotations = 0;
while (!end.get()) {
int bytesToWrite = random.nextInt(1, dataChunk.length);
writer.getChannel().put(dataChunk, bytesToWrite);
if (logFile.rotationNeeded()) {
logFile.rotate();
// Let's just close the gap to the reader so that it gets closer to the "hot zone"
// where the rotation happens.
writer.getCurrentPosition(startPosition);
if (++rotations > LIMIT_ROTATIONS) {
end.set(true);
}
}
}
return null;
});
assertTrue(startSignal.await(10, SECONDS));
// one thread reading through the channel
try {
int reads = 0;
while (!end.get()) {
try (ReadableLogChannel reader = logFile.getReader(startPosition.newPosition())) {
deplete(reader);
}
if (++reads > LIMIT_READS) {
end.set(true);
}
}
} finally {
writeFuture.get();
}
// THEN simply getting here means this was successful
}
use of org.neo4j.storageengine.api.LogVersionRepository in project neo4j by neo4j.
the class LogFilesBuilder method buildContext.
TransactionLogFilesContext buildContext() throws IOException {
if (logEntryReader == null) {
requireNonNull(commandReaderFactory);
logEntryReader = new VersionAwareLogEntryReader(commandReaderFactory);
}
if (config == null) {
config = Config.defaults();
}
requireNonNull(fileSystem);
Supplier<StoreId> storeIdSupplier = getStoreId();
Supplier<LogVersionRepository> logVersionRepositorySupplier = getLogVersionRepositorySupplier();
LongSupplier lastCommittedIdSupplier = lastCommittedIdSupplier();
LongSupplier committingTransactionIdSupplier = committingIdSupplier();
Supplier<LogPosition> lastClosedTransactionPositionSupplier = closePositionSupplier();
// Register listener for rotation threshold
AtomicLong rotationThreshold = getRotationThresholdAndRegisterForUpdates();
AtomicBoolean tryPreallocateTransactionLogs = getTryToPreallocateTransactionLogs();
var nativeAccess = getNativeAccess();
var monitors = getMonitors();
var health = getDatabaseHealth();
var clock = getClock();
// Or the latest version if we can't find the system db version.
if (kernelVersionRepository == null) {
kernelVersionRepository = () -> KernelVersion.LATEST;
if (dependencies != null) {
try {
this.kernelVersionRepository = dependencies.resolveDependency(KernelVersionRepository.class);
} catch (UnsatisfiedDependencyException e) {
// Use latest version if can't find version repository.
}
}
}
return new TransactionLogFilesContext(rotationThreshold, tryPreallocateTransactionLogs, logEntryReader, lastCommittedIdSupplier, committingTransactionIdSupplier, lastClosedTransactionPositionSupplier, logVersionRepositorySupplier, fileSystem, logProvider, databaseTracers, storeIdSupplier, nativeAccess, memoryTracker, monitors, config.get(fail_on_corrupted_log_files), health, kernelVersionRepository, clock, config);
}
use of org.neo4j.storageengine.api.LogVersionRepository in project neo4j by neo4j.
the class LogFilesBuilder method getLogVersionRepositorySupplier.
private Supplier<LogVersionRepository> getLogVersionRepositorySupplier() throws IOException {
if (logVersionRepository != null) {
return () -> logVersionRepository;
}
if (fileBasedOperationsOnly) {
return () -> {
throw new UnsupportedOperationException("Current version of log files can't perform any " + "operation that require availability of log version repository. Please build full version of log files to be able to use them.");
};
}
if (readOnly) {
requireNonNull(pageCache, "Read only log files require page cache to be able to read current log version.");
requireNonNull(databaseLayout, "Store directory is required.");
LogVersionRepository logVersionRepository = readOnlyLogVersionRepository();
return () -> logVersionRepository;
} else {
requireNonNull(dependencies, LogVersionRepository.class.getSimpleName() + " is required. " + "Please provide an instance or a dependencies where it can be found.");
return dependencies.provideDependency(LogVersionRepository.class);
}
}
use of org.neo4j.storageengine.api.LogVersionRepository in project neo4j by neo4j.
the class ReversedSingleFileTransactionCursorTest method setUp.
@BeforeEach
void setUp() throws IOException {
LogVersionRepository logVersionRepository = new SimpleLogVersionRepository();
SimpleTransactionIdStore transactionIdStore = new SimpleTransactionIdStore();
logFiles = LogFilesBuilder.builder(databaseLayout, fs).withRotationThreshold(ByteUnit.mebiBytes(10)).withLogVersionRepository(logVersionRepository).withTransactionIdStore(transactionIdStore).withLogEntryReader(logEntryReader()).withStoreId(StoreId.UNKNOWN).build();
life.add(logFiles);
logFile = logFiles.getLogFile();
}
use of org.neo4j.storageengine.api.LogVersionRepository in project neo4j by neo4j.
the class TransactionLogAppendAndRotateIT method shouldKeepTransactionsIntactWhenConcurrentlyRotationAndAppending.
@Test
void shouldKeepTransactionsIntactWhenConcurrentlyRotationAndAppending() throws Throwable {
// GIVEN
LogVersionRepository logVersionRepository = new SimpleLogVersionRepository();
LogFiles logFiles = LogFilesBuilder.builder(databaseLayout, fileSystem).withLogVersionRepository(logVersionRepository).withRotationThreshold(ByteUnit.mebiBytes(1)).withTransactionIdStore(new SimpleTransactionIdStore()).withLogEntryReader(logEntryReader()).withStoreId(StoreId.UNKNOWN).build();
life.add(logFiles);
final AtomicBoolean end = new AtomicBoolean();
AllTheMonitoring monitoring = new AllTheMonitoring(end, 100);
TransactionIdStore txIdStore = new SimpleTransactionIdStore();
TransactionMetadataCache metadataCache = new TransactionMetadataCache();
monitoring.setLogFile(logFiles.getLogFile());
Health health = new DatabaseHealth(mock(DatabasePanicEventGenerator.class), NullLog.getInstance());
LogRotation rotation = transactionLogRotation(logFiles, Clock.systemUTC(), health, monitoring);
final TransactionAppender appender = life.add(new BatchingTransactionAppender(logFiles, rotation, metadataCache, txIdStore, health));
// WHEN
Race race = new Race();
for (int i = 0; i < 4; i++) {
race.addContestant(() -> {
while (!end.get()) {
try {
appender.append(new TransactionToApply(sillyTransaction(1_000), CursorContext.NULL), LogAppendEvent.NULL);
} catch (Exception e) {
e.printStackTrace(System.out);
end.set(true);
fail(e.getMessage(), e);
}
}
});
}
race.addContestant(endAfterMax(250, MILLISECONDS, end, monitoring));
race.go();
// THEN
assertTrue(monitoring.numberOfRotations() > 0);
}
Aggregations