use of org.neo4j.storageengine.api.CommandsToApply in project neo4j by neo4j.
the class RecordStorageEngineTest method panicOnExceptionDuringCommandsApply.
@Test
void panicOnExceptionDuringCommandsApply() {
IllegalStateException failure = new IllegalStateException("Too many open files");
RecordStorageEngine engine = storageEngineRule.getWith(fs, pageCache, databaseLayout).databaseHealth(databaseHealth).transactionApplierTransformer(facade -> transactionApplierFacadeTransformer(facade, failure)).build();
CommandsToApply commandsToApply = mock(CommandsToApply.class);
var exception = assertThrows(Exception.class, () -> engine.apply(commandsToApply, TransactionApplicationMode.INTERNAL));
assertSame(failure, getRootCause(exception));
verify(databaseHealth).panic(any(Throwable.class));
}
use of org.neo4j.storageengine.api.CommandsToApply in project neo4j by neo4j.
the class RecordStorageEngineTest method shouldCloseLockGroupAfterAppliers.
@Test
void shouldCloseLockGroupAfterAppliers() throws Exception {
// given
long nodeId = 5;
LockService lockService = mock(LockService.class);
Lock nodeLock = mock(Lock.class);
when(lockService.acquireNodeLock(nodeId, EXCLUSIVE)).thenReturn(nodeLock);
// <-- simply so that we can use InOrder mockito construct
Consumer<Boolean> applierCloseCall = mock(Consumer.class);
CapturingTransactionApplierFactoryChain applier = new CapturingTransactionApplierFactoryChain(applierCloseCall);
RecordStorageEngine engine = recordStorageEngineBuilder().lockService(lockService).transactionApplierTransformer(applier::wrapAroundActualApplier).build();
CommandsToApply commandsToApply = mock(CommandsToApply.class);
when(commandsToApply.cursorContext()).thenReturn(NULL);
when(commandsToApply.accept(any())).thenAnswer(invocationOnMock -> {
// Visit one node command
Visitor<StorageCommand, IOException> visitor = invocationOnMock.getArgument(0);
NodeRecord after = new NodeRecord(nodeId);
after.setInUse(true);
visitor.visit(new Command.NodeCommand(new NodeRecord(nodeId), after));
return null;
});
// when
engine.apply(commandsToApply, TransactionApplicationMode.INTERNAL);
// then
InOrder inOrder = inOrder(lockService, applierCloseCall, nodeLock);
inOrder.verify(lockService).acquireNodeLock(nodeId, EXCLUSIVE);
inOrder.verify(applierCloseCall).accept(true);
inOrder.verify(nodeLock).release();
inOrder.verifyNoMoreInteractions();
}
use of org.neo4j.storageengine.api.CommandsToApply in project neo4j by neo4j.
the class RecordStorageEngineTest method executeFailingTransaction.
private static Exception executeFailingTransaction(RecordStorageEngine engine) throws IOException {
Exception applicationError = new UnderlyingStorageException("No space left on device");
CommandsToApply txToApply = newTransactionThatFailsWith(applicationError);
try {
engine.apply(txToApply, TransactionApplicationMode.INTERNAL);
fail("Exception expected");
} catch (Exception e) {
assertSame(applicationError, getRootCause(e));
}
return applicationError;
}
use of org.neo4j.storageengine.api.CommandsToApply in project neo4j by neo4j.
the class TransactionRecordStateTest method shouldWriteProperPropertyRecordsWhenOnlyChangingLinkage.
@Test
void shouldWriteProperPropertyRecordsWhenOnlyChangingLinkage() throws Exception {
neoStores = createStores();
/* There was an issue where GIVEN:
*
* Legend: () = node, [] = property record
*
* ()-->[0:block{size:1}]
*
* WHEN adding a new property record in front of if, not changing any data in that record i.e:
*
* ()-->[1:block{size:4}]-->[0:block{size:1}]
*
* The state of property record 0 would be that it had loaded value records for that block,
* but those value records weren't heavy, so writing that record to the log would fail
* w/ an assertion data != null.
*/
// GIVEN
TransactionRecordState recordState = newTransactionRecordState();
int nodeId = 0;
recordState.nodeCreate(nodeId);
int index = 0;
// will require a block of size 1
recordState.nodeAddProperty(nodeId, index, string(70));
apply(recordState);
// WHEN
recordState = newTransactionRecordState();
int index2 = 1;
// will require a block of size 4
recordState.nodeAddProperty(nodeId, index2, string(40));
// THEN
CommandsToApply representation = transaction(recordState);
representation.accept(command -> ((Command) command).handle(new CommandVisitor.Adapter() {
@Override
public boolean visitPropertyCommand(PropertyCommand command) {
// THEN
verifyPropertyRecord(command.getBefore());
verifyPropertyRecord(command.getAfter());
return false;
}
private void verifyPropertyRecord(PropertyRecord record) {
if (record.getPrevProp() != Record.NO_NEXT_PROPERTY.intValue()) {
for (PropertyBlock block : record) {
assertTrue(block.isLight());
}
}
}
}));
}
use of org.neo4j.storageengine.api.CommandsToApply in project neo4j by neo4j.
the class TransactionRecordStateTest method shouldDeleteDynamicLabelsForDeletedNodeForRecoveredTransaction.
@Test
void shouldDeleteDynamicLabelsForDeletedNodeForRecoveredTransaction() throws Throwable {
neoStores = createStores();
// GIVEN a store that has got a node with a dynamic label record
TransactionApplierFactory applier = buildApplier(LockService.NO_LOCK_SERVICE);
AtomicLong nodeId = new AtomicLong();
AtomicLong dynamicLabelRecordId = new AtomicLong();
apply(applier, transaction(nodeWithDynamicLabelRecord(neoStores, nodeId, dynamicLabelRecordId)));
assertDynamicLabelRecordInUse(neoStores, dynamicLabelRecordId.get(), true);
// WHEN applying a transaction, which has first round-tripped through a log (written then read)
CommandsToApply transaction = transaction(deleteNode(nodeId.get()));
InMemoryVersionableReadableClosablePositionAwareChannel channel = new InMemoryVersionableReadableClosablePositionAwareChannel();
writeToChannel(transaction, channel);
CommandsToApply recoveredTransaction = readFromChannel(channel);
// and applying that recovered transaction
apply(applier, recoveredTransaction);
// THEN should have the dynamic label record should be deleted as well
assertDynamicLabelRecordInUse(neoStores, dynamicLabelRecordId.get(), false);
}
Aggregations