@Override public CompletableFuture<Void> putAllAsync(List<Entry<K, V>> entries) { Preconditions.checkNotNull(writeFn, "null writeFn"); return writeFn.putAllAsync(entries); }
/** * Store the table {@code records} with specified {@code keys}. This method must be thread-safe. * The default implementation calls putAllAsync and blocks on the completion afterwards. * @param records table records to be written */ default void putAll(List<Entry<K, V>> records) { try { putAllAsync(records).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("PUT_ALL failed for " + records, e); } }
/** * Store the table {@code records} with specified {@code keys}. This method must be thread-safe. * The default implementation calls putAllAsync and blocks on the completion afterwards. * @param records table records to be written */ default void putAll(List<Entry<K, V>> records) { try { putAllAsync(records).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("PUT_ALL failed for " + records, e); } }
/** * Store the table {@code records} with specified {@code keys}. This method must be thread-safe. * The default implementation calls putAllAsync and blocks on the completion afterwards. * @param records table records to be written */ default void putAll(List<Entry<K, V>> records) { try { putAllAsync(records).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("PUT_ALL failed for " + records, e); } }
/** * Store the table {@code records} with specified {@code keys}. This method must be thread-safe. * The default implementation calls putAllAsync and blocks on the completion afterwards. * @param records table records to be written */ default void putAll(List<Entry<K, V>> records) { try { putAllAsync(records).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("PUT_ALL failed for " + records, e); } }
/** * Store the table {@code records} with specified {@code keys}. This method must be thread-safe. * The default implementation calls putAllAsync and blocks on the completion afterwards. * @param records table records to be written */ default void putAll(List<Entry<K, V>> records) { try { putAllAsync(records).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("PUT_ALL failed for " + records, e); } }
@Override public CompletableFuture<Void> putAllAsync(Collection<Entry<K, V>> records) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> writeFn.putAllAsync(records)) .exceptionally(e -> { throw new SamzaException("Failed to put records after retries.", e); }); }
@Override public CompletableFuture<Void> putAllAsync(Collection<Entry<K, V>> records) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> writeFn.putAllAsync(records)) .exceptionally(e -> { throw new SamzaException("Failed to put records after retries.", e); }); }
@Override public CompletableFuture<Void> putAllAsync(Collection<Entry<K, V>> records) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> writeFn.putAllAsync(records)) .exceptionally(e -> { throw new SamzaException("Failed to put records after retries.", e); }); }
@Override public CompletableFuture<Void> putAllAsync(Collection<Entry<K, V>> records) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> writeFn.putAllAsync(records)) .exceptionally(e -> { throw new SamzaException("Failed to put records after retries.", e); }); }
@Override public CompletableFuture<Void> putAllAsync(Collection<Entry<K, V>> records) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> writeFn.putAllAsync(records)) .exceptionally(e -> { throw new SamzaException("Failed to put records after retries.", e); }); }
@Test public void testPutAllAsync() { verifyFailure(() -> roTable.putAllAsync(Arrays.asList(new Entry(1, 2)))); rwTable.putAllAsync(Arrays.asList(new Entry(1, 2))); verify(writeFn, times(1)).putAllAsync(any()); }
@Test public void testRetryEngagedPut() throws Exception { String tableId = "testRetryEngagedPut"; TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAllAsync(any()); doReturn(true).when(writeFn).isRetriable(any()); int [] times = new int[] {0}; List<Entry<String, String>> records = new ArrayList<>(); records.add(new Entry<>("foo1", "bar1")); records.add(new Entry<>("foo2", "bar2")); doAnswer(invocation -> { CompletableFuture<Map<String, String>> future = new CompletableFuture(); if (times[0] > 0) { future.complete(null); } else { times[0]++; future.completeExceptionally(new RuntimeException("test exception")); } return future; }).when(writeFn).putAllAsync(any()); RetriableWriteFunction<String, String> retryIO = new RetriableWriteFunction<>(policy, writeFn, schedExec); retryIO.setMetrics(getMetricsUtil(tableId)); retryIO.putAllAsync(records).get(); verify(writeFn, times(2)).putAllAsync(any()); Assert.assertEquals(1, retryIO.retryMetrics.retryCount.getCount()); Assert.assertEquals(0, retryIO.retryMetrics.successCount.getCount()); Assert.assertTrue(retryIO.retryMetrics.retryTimer.getSnapshot().getMax() > 0); }
doReturn(future).when(writeFn).putAllAsync(any()); if (hasDelete) { doReturn(future).when(writeFn).deleteAllAsync(any()); table.putAllAsync(entries).get(); verify(writeFn, times(1)).putAllAsync(argCaptor.capture()); if (hasDelete) { ArgumentCaptor<List> delArgCaptor = ArgumentCaptor.forClass(List.class);
TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAsync(any(), any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAllAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAllAsync(any()); verify(writeFn, times(1)).putAllAsync(any()); verify(writeRateLimiter, times(1)).throttle(anyString(), anyString()); verify(writeRateLimiter, times(1)).throttleRecords(anyList());
@Test public void testPutAllWithOneRetry() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(true).when(writeFn).isRetriable(any()); AtomicInteger times = new AtomicInteger(); doAnswer(invocation -> { CompletableFuture<Map<String, String>> future = new CompletableFuture(); if (times.get() > 0) { future.complete(null); } else { times.incrementAndGet(); future.completeExceptionally(new RuntimeException("test exception")); } return future; }).when(writeFn).putAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); table.putAllAsync(Arrays.asList(new Entry(1, 2))).get(); verify(writeFn, times(2)).putAllAsync(any()); assertEquals(1, table.writeRetryMetrics.retryCount.getCount()); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(0, table.writeRetryMetrics.permFailureCount.getCount()); assertTrue(table.writeRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
doReturn(true).when(writeFn).isRetriable(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAsync(any(), any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAllAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAllAsync(any()); assertEquals(++times, table.writeRetryMetrics.successCount.getCount()); table.putAllAsync(Arrays.asList(new Entry("1", "2"))).get(); verify(writeFn, times(1)).putAllAsync(any()); assertEquals(++times, table.writeRetryMetrics.successCount.getCount()); table.deleteAsync("1").get();
@Test public void testPutWithPermFailureOnMaxCount() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(5)); policy.withStopAfterAttempts(10); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(true).when(writeFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(writeFn).putAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); try { table.putAllAsync(Arrays.asList(new Entry(1, 2))).get(); fail(); } catch (ExecutionException e) { } verify(writeFn, atLeast(11)).putAllAsync(any()); assertEquals(10, table.writeRetryMetrics.retryCount.getCount()); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(1, table.writeRetryMetrics.permFailureCount.getCount()); assertTrue(table.writeRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAllAsync(any()); List<Entry<String, String>> entries = new ArrayList<>(); entries.add(new Entry<>("foo1", "bar111")); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).putAllAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAllAsync(any()); entries = new ArrayList<>();