@Test public void shouldCommitTransactionAndTellRegistryToForgetItsHandle() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); ExecutionEngine engine = mock(ExecutionEngine.class); ExecutionResult result = mock(ExecutionResult.class); when(engine.execute("query", map())).thenReturn(result); TransactionHandle handle = new TransactionHandle(kernel, engine, registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.commit( statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output); // then InOrder transactionOrder = inOrder(transactionContext, registry); transactionOrder.verify(transactionContext).commit(); transactionOrder.verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).statementResult(result, false, (ResultDataContent[]) null); outputOrder.verify(output).errors(argThat(hasNoErrors())); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void getNonExistentKeyReturnsNull() throws Exception { TransactionHandle txn = manager.beginTransaction(); assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col0")); assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col1")); txn.commit(); }
@Test public void shouldSuspendTransactionAndReleaseForOtherRequestsAfterExecutingStatements() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); ExecutionEngine engine = mock(ExecutionEngine.class); ExecutionResult executionResult = mock(ExecutionResult.class); when(engine.execute("query", map())).thenReturn(executionResult); TransactionHandle handle = new TransactionHandle(kernel, engine, registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.execute( statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output); // then InOrder transactionOrder = inOrder(transactionContext, registry); transactionOrder.verify(transactionContext).suspendSinceTransactionsAreStillThreadBound(); transactionOrder.verify(registry).release(1337l, handle); InOrder outputOrder = inOrder(output); outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337)); outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null); outputOrder.verify(output).transactionStatus(anyLong()); outputOrder.verify(output).errors(argThat(hasNoErrors())); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldLogMessageIfCypherSyntaxErrorOccurs() throws Exception { // given KernelAPI kernel = mockKernel(); ExecutionEngine executionEngine = mock(ExecutionEngine.class); when(executionEngine.execute("matsch (n) return n", map())) .thenThrow(new SyntaxException("did you mean MATCH?")); StringLogger log = mock(StringLogger.class); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); TransactionHandle handle = new TransactionHandle(kernel, executionEngine, registry, uriScheme, log); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.commit( statements(new Statement("matsch (n) return n", map(), false, (ResultDataContent[]) null)), output); // then verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).errors(argThat(hasErrors(StatusCode.STATEMENT_SYNTAX_ERROR))); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldExecuteStatements() throws Exception { // given KernelAPI kernel = mockKernel(); ExecutionEngine executionEngine = mock(ExecutionEngine.class); ExecutionResult executionResult = mock(ExecutionResult.class); when(executionEngine.execute("query", map())).thenReturn(executionResult); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); TransactionHandle handle = new TransactionHandle(kernel, executionEngine, registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.execute( statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output); // then verify(executionEngine).execute("query", map()); InOrder outputOrder = inOrder(output); outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337)); outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null); outputOrder.verify(output).transactionStatus(anyLong()); outputOrder.verify(output).errors(argThat(hasNoErrors())); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldRollbackTransactionIfExecutionErrorOccurs() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); ExecutionEngine executionEngine = mock(ExecutionEngine.class); when(executionEngine.execute("query", map())).thenThrow(new NullPointerException()); TransactionHandle handle = new TransactionHandle(kernel, executionEngine, registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.execute( statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output); // then verify(transactionContext).rollback(); verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337)); outputOrder .verify(output) .errors(argThat(hasErrors(StatusCode.INTERNAL_STATEMENT_EXECUTION_ERROR))); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldLogMessageIfCommitErrorOccurs() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); doThrow(new NullPointerException()).when(transactionContext).commit(); StringLogger log = mock(StringLogger.class); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); ExecutionEngine engine = mock(ExecutionEngine.class); ExecutionResult executionResult = mock(ExecutionResult.class); when(engine.execute("query", map())).thenReturn(executionResult); TransactionHandle handle = new TransactionHandle(kernel, engine, registry, uriScheme, log); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.commit( statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output); // then verify(log).error(eq("Failed to commit transaction."), any(NullPointerException.class)); verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null); outputOrder .verify(output) .errors(argThat(hasErrors(StatusCode.INTERNAL_COMMIT_TRANSACTION_ERROR))); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldRollbackTransactionAndTellRegistryToForgetItsHandle() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); TransactionHandle handle = new TransactionHandle( kernel, mock(ExecutionEngine.class), registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.rollback(output); // then InOrder transactionOrder = inOrder(transactionContext, registry); transactionOrder.verify(transactionContext).rollback(); transactionOrder.verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).errors(argThat(hasNoErrors())); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
@Test public void shouldRollbackTransactionIfDeserializationErrorOccurs() throws Exception { // given KernelAPI kernel = mockKernel(); TransitionalTxManagementKernelTransaction transactionContext = (TransitionalTxManagementKernelTransaction) kernel.newTransaction(); TransactionRegistry registry = mock(TransactionRegistry.class); when(registry.begin()).thenReturn(1337l); TransactionHandle handle = new TransactionHandle( kernel, mock(ExecutionEngine.class), registry, uriScheme, StringLogger.DEV_NULL); ExecutionResultSerializer output = mock(ExecutionResultSerializer.class); // when handle.execute( deserilizationErrors(new Neo4jError(StatusCode.INVALID_REQUEST_FORMAT, new Exception())), output); // then verify(transactionContext).rollback(); verify(registry).forget(1337l); InOrder outputOrder = inOrder(output); outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337)); outputOrder.verify(output).errors(argThat(hasErrors(StatusCode.INVALID_REQUEST_FORMAT))); outputOrder.verify(output).finish(); verifyNoMoreInteractions(output); }
private void rollbackSuspended(Predicate<TransactionMarker> predicate) { Set<Long> candidateTransactionIdsToRollback = new HashSet<Long>(); for (Map.Entry<Long, TransactionMarker> entry : registry.entrySet()) { TransactionMarker marker = entry.getValue(); if (marker.isSuspended() && predicate.accept(marker)) { candidateTransactionIdsToRollback.add(entry.getKey()); } } for (long id : candidateTransactionIdsToRollback) { TransactionHandle handle; try { handle = acquire(id); } catch (TransactionLifecycleException invalidTransactionId) { // Allow this - someone snatched the transaction from under our feet, continue; } try { handle.forceRollback(); log.info(format("Transaction with id %d has been automatically rolled back.", id)); } catch (Throwable e) { log.error(format("Transaction with id %d failed to roll back.", id), e); } finally { forget(id); } } }
@Test public void containsKeyReturnsFalseOnNonexistentKey() throws Exception { TransactionHandle txn = manager.beginTransaction(); ByteBuffer key1 = KeyColumnValueStoreUtil.longToByteBuffer(1); assertFalse(store.containsKey(key1.duplicate(), txn)); txn.commit(); }
@Test public void getSliceRespectsAllBoundsInclusionArguments() throws Exception { // Test case where endColumn=startColumn+1 ByteBuffer key = KeyColumnValueStoreUtil.longToByteBuffer(0); ByteBuffer columnBeforeStart = KeyColumnValueStoreUtil.longToByteBuffer(776); ByteBuffer columnStart = KeyColumnValueStoreUtil.longToByteBuffer(777); ByteBuffer columnEnd = KeyColumnValueStoreUtil.longToByteBuffer(778); ByteBuffer columnAfterEnd = KeyColumnValueStoreUtil.longToByteBuffer(779); // First insert four test Entries TransactionHandle txn = manager.beginTransaction(); List<Entry> entries = Arrays.asList( new Entry(columnBeforeStart, columnBeforeStart), new Entry(columnStart, columnStart), new Entry(columnEnd, columnEnd), new Entry(columnAfterEnd, columnAfterEnd)); store.mutate(key, entries, null, txn); txn.commit(); // getSlice() with only start inclusive txn = manager.beginTransaction(); List<Entry> result = store.getSlice(key, columnStart, columnEnd, txn); assertEquals(1, result.size()); assertEquals(777, result.get(0).getColumn().getLong()); txn.commit(); }
@Test public void containsKeyColumnReturnsTrueOnExtantInput() throws Exception { TransactionHandle txn = manager.beginTransaction(); KeyColumnValueStoreUtil.insert(store, txn, 1, "c", "v"); txn.commit(); txn = manager.beginTransaction(); ByteBuffer key1 = KeyColumnValueStoreUtil.longToByteBuffer(1); ByteBuffer c = KeyColumnValueStoreUtil.stringToByteBuffer("c"); assertTrue(store.containsKeyColumn(key1.duplicate(), c.duplicate(), txn)); txn.commit(); }
// This is very very dirty, but do we have a choice? public GraphAwareLongRunningTransaction(TransactionHandle transactionHandle) { this.transactionHandle = transactionHandle; try { Field contextField = transactionHandle.getClass().getDeclaredField("context"); contextField.setAccessible(true); transaction = (TransitionalTxManagementKernelTransaction) contextField.get(transactionHandle); Field registryField = transactionHandle.getClass().getDeclaredField("registry"); registryField.setAccessible(true); registry = (TransactionRegistry) registryField.get(transactionHandle); Field idField = transactionHandle.getClass().getDeclaredField("id"); idField.setAccessible(true); id = (long) idField.get(transactionHandle); } catch (IllegalAccessException | NoSuchFieldException e) { throw new RuntimeException(e); } }
@Test public void insertingGettingAndDeletingSimpleDataWorks() throws Exception { TransactionHandle txn = manager.beginTransaction(); KeyColumnValueStoreUtil.insert(store, txn, 0, "col0", "val0"); KeyColumnValueStoreUtil.insert(store, txn, 0, "col1", "val1"); txn.commit(); txn = manager.beginTransaction(); assertEquals("val0", KeyColumnValueStoreUtil.get(store, txn, 0, "col0")); assertEquals("val1", KeyColumnValueStoreUtil.get(store, txn, 0, "col1")); KeyColumnValueStoreUtil.delete(store, txn, 0, "col0"); KeyColumnValueStoreUtil.delete(store, txn, 0, "col1"); txn.commit(); txn = manager.beginTransaction(); assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col0")); assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col1")); txn.commit(); }
@Test public void getSliceRespectsColumnLimit() throws Exception { TransactionHandle txn = manager.beginTransaction(); ByteBuffer key = KeyColumnValueStoreUtil.longToByteBuffer(0); final int cols = 1024; List<Entry> entries = new LinkedList<Entry>(); for (int i = 0; i < cols; i++) { ByteBuffer col = KeyColumnValueStoreUtil.longToByteBuffer(i); entries.add(new Entry(col, col)); } store.mutate(key, entries, null, txn); txn.commit(); txn = manager.beginTransaction(); ByteBuffer columnStart = KeyColumnValueStoreUtil.longToByteBuffer(0); ByteBuffer columnEnd = KeyColumnValueStoreUtil.longToByteBuffer(cols); /* * When limit is greater than or equal to the matching column count, * all matching columns must be returned. */ List<Entry> result = store.getSlice(key, columnStart, columnEnd, cols, txn); assertEquals(cols, result.size()); assertEquals(entries, result); result = store.getSlice(key, columnStart, columnEnd, cols + 10, txn); assertEquals(cols, result.size()); assertEquals(entries, result); /* * When limit is less the matching column count, the columns up to the * limit (ordered bytewise) must be returned. */ result = store.getSlice(key, columnStart, columnEnd, cols - 1, txn); assertEquals(cols - 1, result.size()); entries.remove(entries.size() - 1); assertEquals(entries, result); result = store.getSlice(key, columnStart, columnEnd, 1, txn); assertEquals(1, result.size()); List<Entry> firstEntrySingleton = Arrays.asList(entries.get(0)); assertEquals(firstEntrySingleton, result); txn.commit(); }
public void close() { if (tx != null) tx.commit(); store.close(); manager.close(); }