Skip to content

Commit fa2beab

Browse files
committed
another version
1 parent 1f3c451 commit fa2beab

File tree

4 files changed

+83
-69
lines changed

4 files changed

+83
-69
lines changed

gax-java/gax/src/main/java/com/google/api/gax/batching/BatchFlusher.java renamed to gax-java/gax/src/main/java/com/google/api/gax/batching/BatchResource.java

+14-13
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,23 @@
3131

3232
import com.google.api.core.InternalApi;
3333

34-
/** A class that determines if the current batch should be flushed. */
34+
/**
35+
* Represent the resource of a batch. Needs to have at least elementCount and byteCount. It's used
36+
* to determine if adding a new element needs to be flow controlled, or if the current batch needs
37+
* to be flushed.
38+
*/
3539
@InternalApi("For google-cloud-java client use only.")
36-
public interface BatchFlusher<ElementT> {
37-
38-
/** Returns true if the batch will be full after adding the element. */
39-
boolean willBeFull(ElementT element);
40+
public interface BatchResource {
4041

41-
/** Increment element counter and byte counter. */
42-
void add(ElementT element);
42+
/** Adds the additional resource. */
43+
BatchResource add(BatchResource resource);
4344

44-
/** Returns true if the batch is empty. */
45-
boolean isEmpty();
45+
/** Returns the element count of this resource. */
46+
long getElementCount();
4647

47-
/** Get the element counter of the current batch. */
48-
long getElementCounter();
48+
/** Returns the byte count of this resource. */
49+
long getByteCount();
4950

50-
/** Get the byte counter of the current batch. */
51-
long getByteCounter();
51+
/** Returns true if the resource is empty. */
52+
boolean isEmpty();
5253
}

gax-java/gax/src/main/java/com/google/api/gax/batching/BatcherImpl.java

+30-20
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ public class BatcherImpl<ElementT, ElementResultT, RequestT, ResponseT>
9595
private final FlowController flowController;
9696
private final ApiCallContext callContext;
9797

98+
private final long elementThreshold;
99+
100+
private final long bytesThreshold;
101+
98102
/**
99103
* @param batchingDescriptor a {@link BatchingDescriptor} for transforming individual elements
100104
* into wrappers request and response
@@ -192,7 +196,7 @@ public BatcherImpl(
192196
+ "#maxOutstandingRequestBytes must be greater or equal to requestByteThreshold");
193197
}
194198
this.flowController = flowController;
195-
currentOpenBatch = new Batch<>(prototype, batchingDescriptor, batchingSettings, batcherStats);
199+
currentOpenBatch = new Batch<>(prototype, batchingDescriptor, batcherStats);
196200
if (batchingSettings.getDelayThreshold() != null) {
197201
long delay = batchingSettings.getDelayThreshold().toMillis();
198202
PushCurrentBatchRunnable<ElementT, ElementResultT, RequestT, ResponseT> runnable =
@@ -204,6 +208,11 @@ public BatcherImpl(
204208
}
205209
currentBatcherReference = new BatcherReference(this);
206210
this.callContext = callContext;
211+
212+
Long elementCountThreshold = batchingSettings.getElementCountThreshold();
213+
this.elementThreshold = elementCountThreshold == null ? 0 : elementCountThreshold;
214+
Long requestByteThreshold = batchingSettings.getRequestByteThreshold();
215+
this.bytesThreshold = requestByteThreshold == null ? 0 : requestByteThreshold;
207216
}
208217

209218
/** {@inheritDoc} */
@@ -213,7 +222,7 @@ public ApiFuture<ElementResultT> add(ElementT element) {
213222
// will only be done from a single calling thread.
214223
Preconditions.checkState(closeFuture == null, "Cannot add elements on a closed batcher");
215224

216-
long bytesSize = batchingDescriptor.countBytes(element);
225+
BatchResource newResource = batchingDescriptor.createResource(element);
217226

218227
// This is not the optimal way of throttling. It does not send out partial batches, which
219228
// means that the Batcher might not use up all the resources allowed by FlowController.
@@ -232,20 +241,22 @@ public ApiFuture<ElementResultT> add(ElementT element) {
232241
// defer it till we decide on if refactoring FlowController is necessary.
233242
Stopwatch stopwatch = Stopwatch.createStarted();
234243
try {
235-
flowController.reserve(1, bytesSize);
244+
flowController.reserve(newResource.getElementCount(), newResource.getByteCount());
236245
} catch (FlowControlException e) {
237246
// This exception will only be thrown if the FlowController is set to ThrowException behavior
238247
throw FlowControlRuntimeException.fromFlowControlException(e);
239248
}
240249
long throttledTimeMs = stopwatch.elapsed(TimeUnit.MILLISECONDS);
241250

242-
if (!currentOpenBatch.isEmpty() && currentOpenBatch.batchFlusher.willBeFull(element)) {
251+
if (!currentOpenBatch.isEmpty()
252+
&& batchingDescriptor.shouldFlush(
253+
currentOpenBatch.resource.add(newResource), elementThreshold, bytesThreshold)) {
243254
sendOutstanding();
244255
}
245256

246257
SettableApiFuture<ElementResultT> result = SettableApiFuture.create();
247258
synchronized (elementLock) {
248-
currentOpenBatch.add(element, result, throttledTimeMs);
259+
currentOpenBatch.add(element, newResource, result, throttledTimeMs);
249260
}
250261

251262
return result;
@@ -268,7 +279,7 @@ public void sendOutstanding() {
268279
return;
269280
}
270281
accumulatedBatch = currentOpenBatch;
271-
currentOpenBatch = new Batch<>(prototype, batchingDescriptor, batchingSettings, batcherStats);
282+
currentOpenBatch = new Batch<>(prototype, batchingDescriptor, batcherStats);
272283
}
273284

274285
// This check is for old clients that instantiated the batcher without ApiCallContext
@@ -293,8 +304,8 @@ public void sendOutstanding() {
293304
public void onSuccess(ResponseT response) {
294305
try {
295306
flowController.release(
296-
accumulatedBatch.batchFlusher.getElementCounter(),
297-
accumulatedBatch.batchFlusher.getByteCounter());
307+
accumulatedBatch.resource.getElementCount(),
308+
accumulatedBatch.resource.getElementCount());
298309
accumulatedBatch.onBatchSuccess(response);
299310
} finally {
300311
onBatchCompletion();
@@ -305,8 +316,8 @@ public void onSuccess(ResponseT response) {
305316
public void onFailure(Throwable throwable) {
306317
try {
307318
flowController.release(
308-
accumulatedBatch.batchFlusher.getElementCounter(),
309-
accumulatedBatch.batchFlusher.getByteCounter());
319+
accumulatedBatch.resource.getElementCount(),
320+
accumulatedBatch.resource.getByteCount());
310321
accumulatedBatch.onBatchFailure(throwable);
311322
} finally {
312323
onBatchCompletion();
@@ -418,31 +429,30 @@ private static class Batch<ElementT, ElementResultT, RequestT, ResponseT> {
418429
private final List<BatchEntry<ElementT, ElementResultT>> entries;
419430
private final BatchingDescriptor<ElementT, ElementResultT, RequestT, ResponseT> descriptor;
420431

421-
private final BatchFlusher<ElementT> batchFlusher;
422432
private final BatcherStats batcherStats;
423433
private long totalThrottledTimeMs = 0;
434+
private BatchResource resource;
424435

425436
private Batch(
426437
RequestT prototype,
427438
BatchingDescriptor<ElementT, ElementResultT, RequestT, ResponseT> descriptor,
428-
BatchingSettings batchingSettings,
429439
BatcherStats batcherStats) {
430440
this.descriptor = descriptor;
431441
this.builder = descriptor.newRequestBuilder(prototype);
432442
this.entries = new ArrayList<>();
433-
Long elementCountThreshold = batchingSettings.getElementCountThreshold();
434-
long elementThreshold = elementCountThreshold == null ? 0 : elementCountThreshold;
435-
Long requestByteThreshold = batchingSettings.getRequestByteThreshold();
436-
long bytesThreshold = requestByteThreshold == null ? 0 : requestByteThreshold;
437-
this.batchFlusher = descriptor.newBatchFlusher(elementThreshold, bytesThreshold);
438443
this.batcherStats = batcherStats;
444+
this.resource = descriptor.createEmptyResource();
439445
}
440446

441-
void add(ElementT element, SettableApiFuture<ElementResultT> result, long throttledTimeMs) {
447+
void add(
448+
ElementT element,
449+
BatchResource newResource,
450+
SettableApiFuture<ElementResultT> result,
451+
long throttledTimeMs) {
442452
builder.add(element);
443453
entries.add(BatchEntry.create(element, result));
444-
batchFlusher.add(element);
445454
totalThrottledTimeMs += throttledTimeMs;
455+
resource = resource.add(newResource);
446456
}
447457

448458
void onBatchSuccess(ResponseT response) {
@@ -466,7 +476,7 @@ void onBatchFailure(Throwable throwable) {
466476
}
467477

468478
boolean isEmpty() {
469-
return batchFlusher.isEmpty();
479+
return resource.isEmpty();
470480
}
471481
}
472482

gax-java/gax/src/main/java/com/google/api/gax/batching/BatchingDescriptor.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,23 @@ public interface BatchingDescriptor<ElementT, ElementResultT, RequestT, Response
9797
/** Returns the size of the passed element object in bytes. */
9898
long countBytes(ElementT element);
9999

100-
/** Creates a new {@link BatchFlusher} to check if the current batch should be flushed. */
101-
default BatchFlusher<ElementT> newBatchFlusher(long elementThreshold, long bytesThreshold) {
102-
return new BatchFlusherImpl<>(this, elementThreshold, bytesThreshold);
100+
/** Creates a new {@link BatchResource} with ElementT. */
101+
default BatchResource createResource(ElementT element) {
102+
return new DefaultBatchResource(1, countBytes(element));
103+
}
104+
105+
/** Create an empty {@link BatchResource}. */
106+
default BatchResource createEmptyResource() {
107+
return new DefaultBatchResource(0, 0);
108+
}
109+
110+
/**
111+
* Checks if the current {@link BatchResource} should be flushed based on the maxElementThreshold
112+
* and maxBytesThreshold.
113+
*/
114+
default boolean shouldFlush(
115+
BatchResource resource, long maxElementThreshold, long maxBytesThreshold) {
116+
return resource.getElementCount() > maxElementThreshold
117+
|| resource.getByteCount() > maxBytesThreshold;
103118
}
104119
}

gax-java/gax/src/main/java/com/google/api/gax/batching/BatchFlusherImpl.java renamed to gax-java/gax/src/main/java/com/google/api/gax/batching/DefaultBatchResource.java

+21-33
Original file line numberDiff line numberDiff line change
@@ -29,53 +29,41 @@
2929
*/
3030
package com.google.api.gax.batching;
3131

32-
import com.google.api.core.InternalApi;
32+
import com.google.common.base.Preconditions;
3333

34-
/** Default implementation of {@link BatchFlusher}. */
35-
@InternalApi("For google-cloud-java client use only.")
36-
public class BatchFlusherImpl<ElementT> implements BatchFlusher<ElementT> {
37-
38-
private final long elementThreshold;
39-
private final long bytesThreshold;
40-
41-
private final BatchingDescriptor<ElementT, ?, ?, ?> batchingDescriptor;
42-
43-
private long elementCounter = 0;
44-
private long byteCounter = 0;
34+
/**
35+
* The default implementation of {@link BatchResource} which tracks the elementCount and byteCount.
36+
*/
37+
final class DefaultBatchResource implements BatchResource {
4538

46-
BatchFlusherImpl(
47-
BatchingDescriptor<ElementT, ?, ?, ?> batchingDescriptor,
48-
long elementThreshold,
49-
long bytesThreshold) {
50-
this.batchingDescriptor = batchingDescriptor;
51-
this.elementThreshold = elementThreshold;
52-
this.bytesThreshold = bytesThreshold;
53-
}
39+
private long elementCount = 0;
40+
private long byteCount = 0;
5441

55-
@Override
56-
public boolean willBeFull(ElementT element) {
57-
return (elementCounter + 1 > elementThreshold)
58-
|| (byteCounter + batchingDescriptor.countBytes(element) > bytesThreshold);
42+
DefaultBatchResource(long elementCount, long byteCount) {
43+
this.elementCount = elementCount;
44+
this.byteCount = byteCount;
5945
}
6046

6147
@Override
62-
public void add(ElementT element) {
63-
elementCounter++;
64-
byteCounter += batchingDescriptor.countBytes(element);
48+
public BatchResource add(BatchResource resource) {
49+
Preconditions.checkArgument(resource instanceof DefaultBatchResource);
50+
this.elementCount += ((DefaultBatchResource) resource).elementCount;
51+
this.byteCount += ((DefaultBatchResource) resource).byteCount;
52+
return this;
6553
}
6654

6755
@Override
68-
public boolean isEmpty() {
69-
return elementCounter == 0;
56+
public long getElementCount() {
57+
return elementCount;
7058
}
7159

7260
@Override
73-
public long getElementCounter() {
74-
return elementCounter;
61+
public long getByteCount() {
62+
return byteCount;
7563
}
7664

7765
@Override
78-
public long getByteCounter() {
79-
return byteCounter;
66+
public boolean isEmpty() {
67+
return elementCount == 0;
8068
}
8169
}

0 commit comments

Comments
 (0)