Skip to content
This repository has been archived by the owner on Nov 14, 2024. It is now read-only.

feature: Expose API to let client define number of expected values in a Get. #6655

Merged
merged 46 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
6c2aa5f
Expose API to let client define number of expected values
LucasIME Jul 4, 2023
99f2125
Add generated changelog entries
svc-changelog Jul 4, 2023
7e76c60
accept revapi change
LucasIME Jul 4, 2023
e3224bd
T -> Timestamp
LucasIME Jul 6, 2023
8d5320d
Extract validation to private method and unsafe log the cells
LucasIME Jul 6, 2023
d3afa8d
fix documentation typo
LucasIME Jul 6, 2023
37ac526
Add cache test
LucasIME Jul 20, 2023
b557bc7
fix test
LucasIME Jul 20, 2023
90477bd
test for not reducing
LucasIME Jul 20, 2023
ffaa25c
description
LucasIME Jul 20, 2023
648e54e
Add methods with cachedLookupRef to TransactionScopedCache gets
LucasIME Jul 20, 2023
f273357
Add test verifying we don't decrease number of expected cells if cach…
LucasIME Jul 20, 2023
773e1ad
verify no lock is ever called
LucasIME Jul 20, 2023
34c0b25
Merge branch 'develop' into lmeireles/expose-get-with-expected-size
LucasIME Jul 20, 2023
0a13148
rev api
LucasIME Jul 20, 2023
d54908e
catch interrupted properly
LucasIME Jul 24, 2023
3d913ff
skip lock check and not lock
LucasIME Jul 24, 2023
797e635
fix test description
LucasIME Jul 24, 2023
2926f79
Array equals instead of !=
LucasIME Jul 24, 2023
e8c08c7
testing all fetched cached
LucasIME Jul 24, 2023
f48fd14
Extract validor to separate class
LucasIME Jul 25, 2023
89cb066
update expected exception class
LucasIME Jul 25, 2023
bf5b271
Add test to verify we throw if we have cached more values than we expect
LucasIME Jul 25, 2023
2739a48
Restrict dangerous API usage
LucasIME Jul 25, 2023
918ead8
rename validator
LucasIME Jul 25, 2023
6a1426f
Treat interrupted and execution exceptions differently.
LucasIME Aug 1, 2023
2ab80f9
Make MoreCellsPresentThanExpectedException SafeLoggable
LucasIME Aug 1, 2023
a42100a
assert args in exception
LucasIME Aug 1, 2023
f91d0ba
cell count validator tests
LucasIME Aug 1, 2023
8f0a05d
add test to verify we don't filter down the cells we pass to the cell…
LucasIME Aug 1, 2023
e147c14
import
LucasIME Aug 1, 2023
9d61cc7
spotless
LucasIME Aug 1, 2023
b2292ce
fix test style
LucasIME Aug 2, 2023
82da62a
Changing getWithExpectedSize to return a Result type (#6686)
LucasIME Aug 4, 2023
ad4d984
Merge branch 'develop' into lmeireles/expose-get-with-expected-size
LucasIME Aug 7, 2023
3227916
rev api
LucasIME Aug 7, 2023
806abe0
Autorelease 0.908.0-rc1
LucasIME Aug 7, 2023
b8d981f
store number of expected cells on exception too
LucasIME Aug 9, 2023
9e25ffa
Autorelease 0.908.0-rc2
LucasIME Aug 9, 2023
11951f1
Merge branch 'develop' into lmeireles/expose-get-with-expected-size
LucasIME Aug 22, 2023
f1912e1
fix ambiguous reference
LucasIME Aug 22, 2023
f11d972
don't count deleted local writes as expected cells
LucasIME Aug 23, 2023
1f68638
Merge branch 'develop' into lmeireles/expose-get-with-expected-size
LucasIME Aug 23, 2023
cad58d2
Autorelease 0.919.0-rc1
LucasIME Aug 23, 2023
b3f7284
Autorelease 0.919.0-rc2
LucasIME Aug 23, 2023
86831da
missing space
LucasIME Aug 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .palantir/revapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,28 @@ acceptedBreaks:
new: "parameter <T> long com.palantir.atlasdb.keyvalue.cassandra.thrift.ThriftObjectSizeUtils::getCollectionSize(java.util.Collection<T>,\
\ ===java.util.function.ToLongFunction<T>===)"
justification: "Avoid autoboxing long to Long"
"0.884.0":
com.palantir.atlasdb:atlasdb-api:
- code: "java.method.addedToInterface"
new: "method java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell, byte[]> com.palantir.atlasdb.transaction.api.Transaction::getWithExpectedNumberOfCells(com.palantir.atlasdb.keyvalue.api.TableReference,\
\ java.util.Set<com.palantir.atlasdb.keyvalue.api.Cell>, int)"
justification: "Just introducing new Get API"
"0.885.0":
com.palantir.atlasdb:atlasdb-api:
- code: "java.method.addedToInterface"
new: "method com.google.common.util.concurrent.ListenableFuture<java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell,\
\ byte[]>> com.palantir.atlasdb.keyvalue.api.cache.TransactionScopedCache::getAsyncWithCachedRef(com.palantir.atlasdb.keyvalue.api.TableReference,\
\ java.util.Set<com.palantir.atlasdb.keyvalue.api.Cell>, java.util.function.Function<com.palantir.atlasdb.keyvalue.api.cache.TransactionScopedCache.CacheLookupResult,\
\ com.google.common.util.concurrent.ListenableFuture<java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell,\
\ byte[]>>>)"
justification: "just adding a new get method"
- code: "java.method.addedToInterface"
new: "method java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell, byte[]> com.palantir.atlasdb.keyvalue.api.cache.TransactionScopedCache::getWithCachedRef(com.palantir.atlasdb.keyvalue.api.TableReference,\
\ java.util.Set<com.palantir.atlasdb.keyvalue.api.Cell>, java.util.function.Function<com.palantir.atlasdb.keyvalue.api.cache.TransactionScopedCache.CacheLookupResult,\
\ com.google.common.util.concurrent.ListenableFuture<java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell,\
\ byte[]>>>)"
justification: "just adding a new get method"
- code: "java.method.addedToInterface"
new: "method java.util.Map<com.palantir.atlasdb.keyvalue.api.Cell, byte[]> com.palantir.atlasdb.transaction.api.Transaction::getWithExpectedNumberOfCells(com.palantir.atlasdb.keyvalue.api.TableReference,\
\ java.util.Set<com.palantir.atlasdb.keyvalue.api.Cell>, long)"
justification: "just adding a new get method"
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public Map<Cell, byte[]> get(
return AtlasFutures.getUnchecked(getAsync(tableReference, cells, valueLoader));
}

@Override
public Map<Cell, byte[]> getWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader) {
return AtlasFutures.getUnchecked(getAsyncWithCachedRef(tableReference, cells, valueLoader));
}

@Override
public ListenableFuture<Map<Cell, byte[]>> getAsync(
TableReference tableReference,
Expand All @@ -59,6 +67,14 @@ public ListenableFuture<Map<Cell, byte[]>> getAsync(
return valueLoader.apply(cells);
}

@Override
public ListenableFuture<Map<Cell, byte[]>> getAsyncWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader) {
return valueLoader.apply(CacheLookupResult.of(Map.of(), cells));
}

@Override
public NavigableMap<byte[], RowResult<byte[]>> getRows(
TableReference tableRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ public Map<Cell, byte[]> get(
return delegate.get(tableReference, cells, valueLoader);
}

@Override
public Map<Cell, byte[]> getWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader) {
return delegate.getWithCachedRef(tableReference, cells, valueLoader);
}

@Override
public ListenableFuture<Map<Cell, byte[]>> getAsync(
TableReference tableReference,
Expand All @@ -64,6 +72,14 @@ public ListenableFuture<Map<Cell, byte[]>> getAsync(
return delegate.getAsync(tableReference, cells, valueLoader);
}

@Override
public ListenableFuture<Map<Cell, byte[]>> getAsyncWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader) {
return delegate.getAsyncWithCachedRef(tableReference, cells, valueLoader);
}

@Override
public NavigableMap<byte[], RowResult<byte[]>> getRows(
TableReference tableRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.NavigableMap;
import java.util.Set;
import java.util.function.Function;
import org.immutables.value.Value;

/**
* The {@link LockWatchValueScopingCache} will provide one of these to every (relevant) transaction, and this will
Expand Down Expand Up @@ -60,11 +61,21 @@ Map<Cell, byte[]> get(
Set<Cell> cells,
Function<Set<Cell>, ListenableFuture<Map<Cell, byte[]>>> valueLoader);

Map<Cell, byte[]> getWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader);
Comment on lines +64 to +67
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could have also just replaced the existing get and getAsync to receive the CacheLookupResult instead of creating new two separate methods. Let me know what you prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How bad would this change have been? Basically I think it's nicer to just have one get/getAsync, but I understand refactoring this might be very difficult/costly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not very, tbh. Although this PR is already getting quite big, so I'll try to do the refactor in a separate one.


ListenableFuture<Map<Cell, byte[]>> getAsync(
TableReference tableReference,
Set<Cell> cells,
Function<Set<Cell>, ListenableFuture<Map<Cell, byte[]>>> valueLoader);

ListenableFuture<Map<Cell, byte[]>> getAsyncWithCachedRef(
TableReference tableReference,
Set<Cell> cells,
Function<CacheLookupResult, ListenableFuture<Map<Cell, byte[]>>> valueLoader);

/**
* The cache will try to fulfil as much of the request as possible with cached values. In the case where some of the
* columns are present in the cache for a row, the cellLoader will be used to read the remaining cells remotely.
Expand Down Expand Up @@ -93,4 +104,18 @@ NavigableMap<byte[], RowResult<byte[]>> getRows(
HitDigest getHitDigest();

TransactionScopedCache createReadOnlyCache(CommitUpdate commitUpdate);

@Value.Immutable
interface CacheLookupResult {
Map<Cell, CacheValue> cacheHits();

Set<Cell> missedCells();

static CacheLookupResult of(Map<Cell, CacheValue> cachedValues, Set<Cell> missedCells) {
return ImmutableCacheLookupResult.builder()
.cacheHits(cachedValues)
.missedCells(missedCells)
.build();
}
}
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.palantir.atlasdb.transaction.api;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.errorprone.annotations.RestrictedApi;
import com.palantir.atlasdb.keyvalue.api.BatchColumnRangeSelection;
import com.palantir.atlasdb.keyvalue.api.Cell;
import com.palantir.atlasdb.keyvalue.api.ColumnRangeSelection;
Expand All @@ -24,6 +25,7 @@
import com.palantir.atlasdb.keyvalue.api.RowResult;
import com.palantir.atlasdb.keyvalue.api.TableReference;
import com.palantir.atlasdb.spi.KeyValueServiceConfig;
import com.palantir.atlasdb.transaction.api.annotations.ReviewedRestrictedApiUsage;
import com.palantir.atlasdb.transaction.service.TransactionService;
import com.palantir.common.annotation.Idempotent;
import com.palantir.common.base.BatchingVisitable;
Expand Down Expand Up @@ -175,6 +177,41 @@ Iterator<Map.Entry<Cell, byte[]>> getSortedColumns(
@Idempotent
Map<Cell, byte[]> get(TableReference tableRef, Set<Cell> cells);

/**
* Similar to {@link #get(TableReference, Set)}, but allows the caller to specify the number of expected present
* cells. This is important to allow clients that might have schemas that guarantees only a subset of the columns
* are present to still benefit from being able to skip the immutable timestamp lock check on non-empty reads of
* thoroughly swept tables.
*
* If we find values for the exact number of expected present cells, we'll skip the immutable timestamp lock check.
* If we find less values, we'll perform the immutable timestamp lock check.
* If we find more values, we'll throw an exception, as it means that either:
* 1 - There is a bug in the implementation of this method.
* 2 - The client is making an incorrect assumption about the maximum number of values that will be present, and
* we could have returned empty values in the past when we should have not.
*
* WARNING: This method should only be used if you REALLY know what you're doing. Otherwise, you could have
* correctness issues by reading empty values when one is actually present if you don't use this method correctly.
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
*
* @param tableRef the table from which to get the values
* @param cells the cells for which we want to get the values
* @param expectedNumberOfPresentCells the maximum number of cells that are expected to be present.
* @return a {@link Map} from {@link Cell} to {@code byte[]} representing cell/value pairs
*/
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
@RestrictedApi(
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
explanation = "This API is only meant to be used by AtlasDb proxies that want to make usage of the "
+ "performance improvement of skipping the immutable timestamp lock check on non-empty reads of "
+ "thoroughly swept tables, but their schema won't allow them to have non empty reads due to "
+ "columns being mutually exclusive, for example. So this API gives them a good way to specifying "
+ "the max number of values they'd ever expect in a get, which when met would allow them to skip "
+ "the lock check. Wrong usage of this API can cause correctness issues, so it's restricted.",
link = "https://github.com/palantir/atlasdb/pull/6655",
allowedOnPath = ".*/src/test/.*", // Unsafe behavior in tests is ok.
allowlistAnnotations = {ReviewedRestrictedApiUsage.class})
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
@Idempotent
Map<Cell, byte[]> getWithExpectedNumberOfCells(
TableReference tableRef, Set<Cell> cells, long expectedNumberOfPresentCells);

/**
* Gets the values associated for each cell in {@code cells} from table specified by {@code tableRef}. It is not
* guaranteed that the actual implementations are in fact asynchronous.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* (c) Copyright 2023 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.palantir.atlasdb.transaction.api.annotations;

/**
* Annotation to be used to indicate that usage of a restricted method is intentional and all the nuances about it
* are understood.
*/
public @interface ReviewedRestrictedApiUsage {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* (c) Copyright 2023 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.palantir.atlasdb.transaction.api.exceptions;

import com.palantir.atlasdb.keyvalue.api.Cell;
import com.palantir.logsafe.Arg;
import com.palantir.logsafe.Safe;
import com.palantir.logsafe.SafeArg;
import com.palantir.logsafe.SafeLoggable;
import com.palantir.logsafe.Unsafe;
import com.palantir.logsafe.UnsafeArg;
import com.palantir.logsafe.exceptions.SafeExceptions;
import java.util.List;
import java.util.Map;

public final class MoreCellsPresentThanExpectedException extends IllegalStateException implements SafeLoggable {

private static final String MESSAGE =
"KeyValueService returned more results than Get expected. This means there is a bug"
+ "either in the SnapshotTransaction implementation or in how the client is "
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
+ "using such method.";
private final List<Arg<?>> arguments;
private final Map<Cell, byte[]> fetchedCells;

public MoreCellsPresentThanExpectedException(Map<Cell, byte[]> fetchedCells, long expectedNumberOfCells) {
super(SafeExceptions.renderMessage(
MESSAGE, argsFrom(fetchedCells, expectedNumberOfCells).toArray(Arg<?>[]::new)));
this.fetchedCells = fetchedCells;
this.arguments = argsFrom(fetchedCells, expectedNumberOfCells);
}

public Map<Cell, byte[]> getFetchedCells() {
return fetchedCells;
}

@Override
public @Safe String getLogMessage() {
return MESSAGE;
}

@Override
public List<Arg<?>> getArgs() {
return arguments;
}

@Unsafe
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the @Unsafe marker here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the SafeLoggingPropagation check. Otherwise we fail to compile with the following message:

/Volumes/git/Projects/atlasdb/atlasdb-api/src/main/java/com/palantir/atlasdb/transaction/api/exceptions/MoreCellsPresentThanExpectedException.java:59: error: [SafeLoggingPropagation] Safe logging annotations should be propagated to encapsulating elements to allow static analysis tooling to work with as much information as possible. This check can be auto-fixed using `./gradlew classes testClasses -PerrorProneApply=SafeLoggingPropagation`
    private static List<Arg<?>> argsFrom(Map<Cell, byte[]> retrievedCells, long expectedNumberOfCells) {
                                ^
    (see https://github.com/palantir/gradle-baseline#baseline-error-prone-checks)
  Did you mean '@Unsafe private static List<Arg<?>> argsFrom(Map<Cell, byte[]> retrievedCells, long expectedNumberOfCells) {'?

private static List<Arg<?>> argsFrom(Map<Cell, byte[]> retrievedCells, long expectedNumberOfCells) {
return List.of(
SafeArg.of("expectedNumberOfCells", expectedNumberOfCells),
SafeArg.of("numberOfCellsRetrieved", retrievedCells.size()),
UnsafeArg.of("retrievedCells", retrievedCells));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
import com.palantir.atlasdb.keyvalue.impl.Cells;
import com.palantir.atlasdb.transaction.api.Transaction;
import com.palantir.atlasdb.transaction.api.TransactionFailedException;
import com.palantir.atlasdb.transaction.api.annotations.ReviewedRestrictedApiUsage;
import com.palantir.atlasdb.transaction.service.TransactionService;
import com.palantir.common.base.Throwables;
import com.palantir.logsafe.SafeArg;
import com.palantir.logsafe.logger.SafeLogger;
import com.palantir.logsafe.logger.SafeLoggerFactory;
import com.palantir.util.Pair;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
Expand Down Expand Up @@ -124,16 +126,42 @@ public Map<Cell, byte[]> get(TableReference tableRef, Set<Cell> cells) {
return getWithLoader(
tableRef,
cells,
(tableReference, toRead) -> Futures.immediateFuture(super.get(tableReference, toRead)))
(tableReference, _cachedCells, toRead) ->
Futures.immediateFuture(super.get(tableReference, toRead)))
.get();
} catch (InterruptedException | ExecutionException e) {
} catch (InterruptedException e) {
throw Throwables.rewrapAndThrowUncheckedException(e);
} catch (ExecutionException e) {
throw Throwables.rewrapAndThrowUncheckedException(e.getCause());
LucasIME marked this conversation as resolved.
Show resolved Hide resolved
}
}

@ReviewedRestrictedApiUsage
@Override
public Map<Cell, byte[]> getWithExpectedNumberOfCells(
TableReference tableRef, Set<Cell> cells, long expectedNumberOfPresentCells) {
try {
return getWithLoader(tableRef, cells, (tableReference, cachedCells, toRead) -> {
long nonEmptyValuesInCache = cachedCells.values().stream()
.filter(value -> !Arrays.equals(value, PtBytes.EMPTY_BYTE_ARRAY))
.count();
long numberOfCellsExpectingValuePostCache =
expectedNumberOfPresentCells - nonEmptyValuesInCache;

return Futures.immediateFuture(super.getWithExpectedNumberOfCells(
tableReference, toRead, numberOfCellsExpectingValuePostCache));
})
.get();
} catch (InterruptedException e) {
throw Throwables.rewrapAndThrowUncheckedException(e);
} catch (ExecutionException e) {
throw Throwables.rewrapAndThrowUncheckedException(e.getCause());
}
}

@Override
public ListenableFuture<Map<Cell, byte[]>> getAsync(TableReference tableRef, Set<Cell> cells) {
return getWithLoader(tableRef, cells, super::getAsync);
return getWithLoader(tableRef, cells, (table, _cacheCells, cellsToLoad) -> super.getAsync(table, cellsToLoad));
}

private ListenableFuture<Map<Cell, byte[]>> getWithLoader(
Expand All @@ -156,7 +184,7 @@ private ListenableFuture<Map<Cell, byte[]>> getWithLoader(
}

return Futures.transform(
cellLoader.load(tableRef, toLoad),
cellLoader.load(tableRef, cacheHit, toLoad),
loadedCells -> {
cacheLoadedCells(tableRef, toLoad, loadedCells);
cacheHit.putAll(loadedCells);
Expand Down Expand Up @@ -271,6 +299,7 @@ public void abort() {

@FunctionalInterface
private interface CellLoader {
ListenableFuture<Map<Cell, byte[]>> load(TableReference tableReference, Set<Cell> toRead);
ListenableFuture<Map<Cell, byte[]>> load(
TableReference tableReference, Map<Cell, byte[]> cachedCells, Set<Cell> toRead);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.palantir.atlasdb.transaction.api.Transaction;
import com.palantir.atlasdb.transaction.api.TransactionFailedException;
import com.palantir.atlasdb.transaction.api.TransactionReadSentinelBehavior;
import com.palantir.atlasdb.transaction.api.annotations.ReviewedRestrictedApiUsage;
import com.palantir.atlasdb.transaction.service.TransactionService;
import com.palantir.common.base.BatchingVisitable;
import java.util.Iterator;
Expand Down Expand Up @@ -83,6 +84,13 @@ public Map<Cell, byte[]> get(TableReference tableRef, Set<Cell> cells) {
return delegate().get(tableRef, cells);
}

@ReviewedRestrictedApiUsage
@Override
public Map<Cell, byte[]> getWithExpectedNumberOfCells(
TableReference tableRef, Set<Cell> cells, long expectedNumberOfPresentCells) {
return delegate().getWithExpectedNumberOfCells(tableRef, cells, expectedNumberOfPresentCells);
}

@Override
public BatchingVisitable<RowResult<byte[]>> getRange(TableReference tableRef, RangeRequest rangeRequest) {
return delegate().getRange(tableRef, rangeRequest);
Expand Down
Loading