@Override public CompletableFuture<V> getAsync(K key) { return readFn.getAsync(key); }
/** * Fetch single table record for a specified {@code key}. This method must be thread-safe. * The default implementation calls getAsync and blocks on the completion afterwards. * @param key key for the table record * @return table record for the specified {@code key} */ default V get(K key) { try { return getAsync(key).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("GET failed for " + key, e); } }
/** * Fetch single table record for a specified {@code key}. This method must be thread-safe. * The default implementation calls getAsync and blocks on the completion afterwards. * @param key key for the table record * @return table record for the specified {@code key} */ default V get(K key) { try { return getAsync(key).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("GET failed for " + key, e); } }
/** * Fetch single table record for a specified {@code key}. This method must be thread-safe. * The default implementation calls getAsync and blocks on the completion afterwards. * @param key key for the table record * @return table record for the specified {@code key} */ default V get(K key) { try { return getAsync(key).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("GET failed for " + key, e); } }
/** * Fetch single table record for a specified {@code key}. This method must be thread-safe. * The default implementation calls getAsync and blocks on the completion afterwards. * @param key key for the table record * @return table record for the specified {@code key} */ default V get(K key) { try { return getAsync(key).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("GET failed for " + key, e); } }
/** * Fetch single table record for a specified {@code key}. This method must be thread-safe. * The default implementation calls getAsync and blocks on the completion afterwards. * @param key key for the table record * @return table record for the specified {@code key} */ default V get(K key) { try { return getAsync(key).get(); } catch (InterruptedException | ExecutionException e) { throw new SamzaException("GET failed for " + key, e); } }
/** * Asynchronously fetch the table {@code records} for specified {@code keys}. This method must be thread-safe. * The default implementation calls getAsync for each key and return a combined future. * @param keys keys for the table records * @return CompletableFuture for the get request */ default CompletableFuture<Map<K, V>> getAllAsync(Collection<K> keys) { Map<K, CompletableFuture<V>> getFutures = keys.stream().collect( Collectors.toMap(k -> k, k -> getAsync(k))); return CompletableFuture.allOf( Iterables.toArray(getFutures.values(), CompletableFuture.class)) .thenApply(future -> getFutures.entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().join()))); }
/** * Asynchronously fetch the table {@code records} for specified {@code keys}. This method must be thread-safe. * The default implementation calls getAsync for each key and return a combined future. * @param keys keys for the table records * @return CompletableFuture for the get request */ default CompletableFuture<Map<K, V>> getAllAsync(Collection<K> keys) { Map<K, CompletableFuture<V>> getFutures = keys.stream().collect( Collectors.toMap(k -> k, k -> getAsync(k))); return CompletableFuture.allOf( Iterables.toArray(getFutures.values(), CompletableFuture.class)) .thenApply(future -> getFutures.entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().join()))); }
/** * Asynchronously fetch the table {@code records} for specified {@code keys}. This method must be thread-safe. * The default implementation calls getAsync for each key and return a combined future. * @param keys keys for the table records * @return CompletableFuture for the get request */ default CompletableFuture<Map<K, V>> getAllAsync(Collection<K> keys) { Map<K, CompletableFuture<V>> getFutures = keys.stream().collect( Collectors.toMap(k -> k, k -> getAsync(k))); return CompletableFuture.allOf( Iterables.toArray(getFutures.values(), CompletableFuture.class)) .thenApply(future -> getFutures.entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().join()))); }
/** * Asynchronously fetch the table {@code records} for specified {@code keys}. This method must be thread-safe. * The default implementation calls getAsync for each key and return a combined future. * @param keys keys for the table records * @return CompletableFuture for the get request */ default CompletableFuture<Map<K, V>> getAllAsync(Collection<K> keys) { Map<K, CompletableFuture<V>> getFutures = keys.stream().collect( Collectors.toMap(k -> k, k -> getAsync(k))); return CompletableFuture.allOf( Iterables.toArray(getFutures.values(), CompletableFuture.class)) .thenApply(future -> getFutures.entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().join()))); }
/** * Asynchronously fetch the table {@code records} for specified {@code keys}. This method must be thread-safe. * The default implementation calls getAsync for each key and return a combined future. * @param keys keys for the table records * @return CompletableFuture for the get request */ default CompletableFuture<Map<K, V>> getAllAsync(Collection<K> keys) { Map<K, CompletableFuture<V>> getFutures = keys.stream().collect( Collectors.toMap(k -> k, k -> getAsync(k))); return CompletableFuture.allOf( Iterables.toArray(getFutures.values(), CompletableFuture.class)) .thenApply(future -> getFutures.entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().join()))); }
@Override public CompletableFuture<V> getAsync(K key) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> readFn.getAsync(key)) .exceptionally(e -> { throw new SamzaException("Failed to get the record for " + key + " after retries.", e); }); }
@Override public CompletableFuture<V> getAsync(K key) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> readFn.getAsync(key)) .exceptionally(e -> { throw new SamzaException("Failed to get the record for " + key + " after retries.", e); }); }
@Override public CompletableFuture<V> getAsync(K key) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> readFn.getAsync(key)) .exceptionally(e -> { throw new SamzaException("Failed to get the record for " + key + " after retries.", e); }); }
@Override public CompletableFuture<V> getAsync(K key) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> readFn.getAsync(key)) .exceptionally(e -> { throw new SamzaException("Failed to get the record for " + key + " after retries.", e); }); }
@Override public CompletableFuture<V> getAsync(K key) { return failsafe(retryPolicy, retryMetrics, retryExecutor) .future(() -> readFn.getAsync(key)) .exceptionally(e -> { throw new SamzaException("Failed to get the record for " + key + " after retries.", e); }); }
@Test public void testGetWithCallbackExecutor() throws Exception { TableReadFunction<String, String> readFn = mock(TableReadFunction.class); // Sync is backed by async so needs to mock the async method doReturn(CompletableFuture.completedFuture("bar")).when(readFn).getAsync(anyString()); RemoteTable<String, String> table = getTable("testGetWithCallbackExecutor", readFn, null, Executors.newSingleThreadExecutor(), false); Thread testThread = Thread.currentThread(); table.getAsync("foo").thenAccept(result -> { Assert.assertEquals("bar", result); // Must be executed on the executor thread Assert.assertNotSame(testThread, Thread.currentThread()); }); } }
@Test public void testGetMultipleTables() { TableReadFunction<String, String> readFn1 = mock(TableReadFunction.class); TableReadFunction<String, String> readFn2 = mock(TableReadFunction.class); // Sync is backed by async so needs to mock the async method doReturn(CompletableFuture.completedFuture("bar1")).when(readFn1).getAsync(anyString()); doReturn(CompletableFuture.completedFuture("bar2")).when(readFn1).getAsync(anyString()); RemoteTable<String, String> table1 = getTable("testGetMultipleTables-1", readFn1, null, false); RemoteTable<String, String> table2 = getTable("testGetMultipleTables-2", readFn2, null, false); CompletableFuture<String> future1 = table1.getAsync("foo1"); CompletableFuture<String> future2 = table2.getAsync("foo2"); CompletableFuture.allOf(future1, future2) .thenAccept(u -> { Assert.assertEquals(future1.join(), "bar1"); Assert.assertEquals(future2.join(), "bar1"); }); }
@Test public void testFirstTimeSuccessGet() throws Exception { String tableId = "testFirstTimeSuccessGet"; TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(100)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(true).when(readFn).isRetriable(any()); doReturn(CompletableFuture.completedFuture("bar")).when(readFn).getAsync(anyString()); RetriableReadFunction<String, String> retryIO = new RetriableReadFunction<>(policy, readFn, schedExec); retryIO.setMetrics(getMetricsUtil(tableId)); Assert.assertEquals("bar", retryIO.getAsync("foo").get()); verify(readFn, times(1)).getAsync(anyString()); Assert.assertEquals(0, retryIO.retryMetrics.retryCount.getCount()); Assert.assertEquals(1, retryIO.retryMetrics.successCount.getCount()); Assert.assertEquals(0, retryIO.retryMetrics.retryTimer.getSnapshot().getMax()); }