use of org.neo4j.kernel.lifecycle.LifeSupport in project neo4j by neo4j.
the class HighAvailabilityModeSwitcher method switchToDetached.
private void switchToDetached() {
msgLog.info("I am %s, moving to detached", instanceId);
startModeSwitching(() -> {
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to pending cancelled on start.");
return;
}
componentSwitcher.switchToSlave();
neoStoreDataSourceSupplier.getDataSource().beforeModeSwitch();
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to pending cancelled before ha communication shutdown.");
return;
}
haCommunicationLife.shutdown();
haCommunicationLife = new LifeSupport();
}, new CancellationHandle());
try {
modeSwitcherFuture.get(10, TimeUnit.SECONDS);
} catch (Exception e) {
msgLog.warn("Exception received while waiting for switching to detached", e);
}
}
use of org.neo4j.kernel.lifecycle.LifeSupport in project neo4j by neo4j.
the class HighAvailabilityModeSwitcher method switchToPending.
private void switchToPending(final HighAvailabilityMemberState oldState) {
msgLog.info("I am %s, moving to pending", instanceId);
startModeSwitching(() -> {
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to pending cancelled on start.");
return;
}
componentSwitcher.switchToPending();
neoStoreDataSourceSupplier.getDataSource().beforeModeSwitch();
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to pending cancelled before ha communication shutdown.");
return;
}
haCommunicationLife.shutdown();
haCommunicationLife = new LifeSupport();
}, new CancellationHandle());
try {
modeSwitcherFuture.get(10, TimeUnit.SECONDS);
} catch (Exception ignored) {
}
}
use of org.neo4j.kernel.lifecycle.LifeSupport in project neo4j by neo4j.
the class HighAvailabilityModeSwitcher method switchToSlave.
private void switchToSlave() {
/*
* This is purely defensive and should never trigger. There was a race where the switch to slave task would
* start after this instance was elected master and the task would constantly try to change as slave
* for itself, never cancelling. This now should not be possible, since we cancel the task and wait for it
* to complete, all in a single thread executor. However, this is a check worth doing because if this
* condition slips through via some other code path it can cause trouble.
*/
if (getServerId(availableMasterId).equals(instanceId)) {
msgLog.error("I (" + me + ") tried to switch to slave for myself as master (" + availableMasterId + ")");
return;
}
final AtomicLong wait = new AtomicLong();
final CancellationHandle cancellationHandle = new CancellationHandle();
startModeSwitching(new Runnable() {
@Override
public void run() {
if (currentTargetState != HighAvailabilityMemberState.TO_SLAVE) {
// Already switched - this can happen if a second master becomes available while waiting
return;
}
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to slave cancelled on start.");
return;
}
componentSwitcher.switchToSlave();
try {
if (cancellationHandle.cancellationRequested()) {
msgLog.info("Switch to slave cancelled before ha communication started.");
return;
}
haCommunicationLife.shutdown();
haCommunicationLife = new LifeSupport();
// it is important for availableMasterId to be re-read on every attempt so that
// slave switching would not result in an infinite loop with wrong/stale availableMasterId
URI resultingSlaveHaURI = switchToSlave.switchToSlave(haCommunicationLife, me, availableMasterId, cancellationHandle);
if (resultingSlaveHaURI == null) {
/*
* null slave uri means the task was cancelled. The task then must simply terminate and
* have no side effects.
*/
msgLog.info("Switch to slave is effectively cancelled");
} else {
slaveHaURI = resultingSlaveHaURI;
canAskForElections.set(true);
}
} catch (HighAvailabilityStoreFailureException e) {
userLog.error("UNABLE TO START UP AS SLAVE: %s", e.getMessage());
msgLog.error("Unable to start up as slave", e);
clusterMemberAvailability.memberIsUnavailable(SLAVE);
ClusterClient clusterClient = HighAvailabilityModeSwitcher.this.clusterClient;
try {
// TODO I doubt this actually works
clusterClient.leave();
clusterClient.stop();
haCommunicationLife.shutdown();
} catch (Throwable t) {
msgLog.error("Unable to stop cluster client", t);
}
modeSwitcherExecutor.schedule(this, 5, TimeUnit.SECONDS);
} catch (MismatchingStoreIdException e) {
// Try again immediately, the place that threw it have already treated the db
// as branched and so a new attempt will have this slave copy a new store from master.
run();
} catch (Throwable t) {
msgLog.error("Error while trying to switch to slave", t);
// Try again later
// Exponential backoff
wait.set(1 + wait.get() * 2);
// Wait maximum 5 minutes
wait.set(Math.min(wait.get(), 5 * 60));
modeSwitcherFuture = modeSwitcherExecutor.schedule(this, wait.get(), TimeUnit.SECONDS);
msgLog.info("Attempting to switch to slave in %ds", wait.get());
}
}
}, cancellationHandle);
}
use of org.neo4j.kernel.lifecycle.LifeSupport in project neo4j by neo4j.
the class PhysicalLogFileTest method shouldOpenInFreshDirectoryAndFinallyAddHeader.
@Test
public void shouldOpenInFreshDirectoryAndFinallyAddHeader() throws Exception {
// GIVEN
String name = "log";
LifeSupport life = new LifeSupport();
FileSystemAbstraction fs = fileSystemRule.get();
PhysicalLogFiles logFiles = new PhysicalLogFiles(directory.directory(), name, fs);
life.add(new PhysicalLogFile(fs, logFiles, 1000, transactionIdStore::getLastCommittedTransactionId, logVersionRepository, mock(Monitor.class), new LogHeaderCache(10)));
// WHEN
life.start();
life.shutdown();
// THEN
File file = new PhysicalLogFiles(directory.directory(), name, fs).getLogFileForVersion(1L);
LogHeader header = readLogHeader(fs, file);
assertEquals(1L, header.logVersion);
assertEquals(5L, header.lastCommittedTxId);
}
use of org.neo4j.kernel.lifecycle.LifeSupport in project neo4j by neo4j.
the class PhysicalLogFileTest method shouldWriteSomeDataIntoTheLog.
@Test
public void shouldWriteSomeDataIntoTheLog() throws Exception {
// GIVEN
String name = "log";
LifeSupport life = new LifeSupport();
FileSystemAbstraction fs = fileSystemRule.get();
PhysicalLogFiles logFiles = new PhysicalLogFiles(directory.directory(), name, fs);
Monitor monitor = mock(Monitor.class);
LogFile logFile = life.add(new PhysicalLogFile(fs, logFiles, 1000, transactionIdStore::getLastCommittedTransactionId, logVersionRepository, monitor, new LogHeaderCache(10)));
// WHEN
try {
life.start();
FlushablePositionAwareChannel writer = logFile.getWriter();
LogPositionMarker positionMarker = new LogPositionMarker();
writer.getCurrentPosition(positionMarker);
int intValue = 45;
long longValue = 4854587;
writer.putInt(intValue);
writer.putLong(longValue);
writer.prepareForFlush().flush();
// THEN
try (ReadableClosableChannel reader = logFile.getReader(positionMarker.newPosition())) {
assertEquals(intValue, reader.getInt());
assertEquals(longValue, reader.getLong());
}
} finally {
life.shutdown();
}
}
Aggregations