@@ -95,6 +95,10 @@ public class BatcherImpl<ElementT, ElementResultT, RequestT, ResponseT>
95
95
private final FlowController flowController ;
96
96
private final ApiCallContext callContext ;
97
97
98
+ private final long elementThreshold ;
99
+
100
+ private final long bytesThreshold ;
101
+
98
102
/**
99
103
* @param batchingDescriptor a {@link BatchingDescriptor} for transforming individual elements
100
104
* into wrappers request and response
@@ -192,7 +196,7 @@ public BatcherImpl(
192
196
+ "#maxOutstandingRequestBytes must be greater or equal to requestByteThreshold" );
193
197
}
194
198
this .flowController = flowController ;
195
- currentOpenBatch = new Batch <>(prototype , batchingDescriptor , batchingSettings , batcherStats );
199
+ currentOpenBatch = new Batch <>(prototype , batchingDescriptor , batcherStats );
196
200
if (batchingSettings .getDelayThreshold () != null ) {
197
201
long delay = batchingSettings .getDelayThreshold ().toMillis ();
198
202
PushCurrentBatchRunnable <ElementT , ElementResultT , RequestT , ResponseT > runnable =
@@ -204,6 +208,11 @@ public BatcherImpl(
204
208
}
205
209
currentBatcherReference = new BatcherReference (this );
206
210
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 ;
207
216
}
208
217
209
218
/** {@inheritDoc} */
@@ -213,7 +222,7 @@ public ApiFuture<ElementResultT> add(ElementT element) {
213
222
// will only be done from a single calling thread.
214
223
Preconditions .checkState (closeFuture == null , "Cannot add elements on a closed batcher" );
215
224
216
- long bytesSize = batchingDescriptor .countBytes (element );
225
+ BatchResource newResource = batchingDescriptor .createResource (element );
217
226
218
227
// This is not the optimal way of throttling. It does not send out partial batches, which
219
228
// means that the Batcher might not use up all the resources allowed by FlowController.
@@ -232,7 +241,7 @@ public ApiFuture<ElementResultT> add(ElementT element) {
232
241
// defer it till we decide on if refactoring FlowController is necessary.
233
242
Stopwatch stopwatch = Stopwatch .createStarted ();
234
243
try {
235
- flowController .reserve (1 , bytesSize );
244
+ flowController .reserve (newResource . getElementCount (), newResource . getByteCount () );
236
245
} catch (FlowControlException e ) {
237
246
// This exception will only be thrown if the FlowController is set to ThrowException behavior
238
247
throw FlowControlRuntimeException .fromFlowControlException (e );
@@ -241,12 +250,15 @@ public ApiFuture<ElementResultT> add(ElementT element) {
241
250
242
251
SettableApiFuture <ElementResultT > result = SettableApiFuture .create ();
243
252
synchronized (elementLock ) {
244
- currentOpenBatch .add (element , result , throttledTimeMs );
245
- }
253
+ if (!currentOpenBatch .isEmpty ()
254
+ && batchingDescriptor .shouldFlush (
255
+ currentOpenBatch .resource .add (newResource ), elementThreshold , bytesThreshold )) {
256
+ sendOutstanding ();
257
+ }
246
258
247
- if (currentOpenBatch .hasAnyThresholdReached ()) {
248
- sendOutstanding ();
259
+ currentOpenBatch .add (element , newResource , result , throttledTimeMs );
249
260
}
261
+
250
262
return result ;
251
263
}
252
264
@@ -267,7 +279,7 @@ public void sendOutstanding() {
267
279
return ;
268
280
}
269
281
accumulatedBatch = currentOpenBatch ;
270
- currentOpenBatch = new Batch <>(prototype , batchingDescriptor , batchingSettings , batcherStats );
282
+ currentOpenBatch = new Batch <>(prototype , batchingDescriptor , batcherStats );
271
283
}
272
284
273
285
// This check is for old clients that instantiated the batcher without ApiCallContext
@@ -291,7 +303,9 @@ public void sendOutstanding() {
291
303
@ Override
292
304
public void onSuccess (ResponseT response ) {
293
305
try {
294
- flowController .release (accumulatedBatch .elementCounter , accumulatedBatch .byteCounter );
306
+ flowController .release (
307
+ accumulatedBatch .resource .getElementCount (),
308
+ accumulatedBatch .resource .getByteCount ());
295
309
accumulatedBatch .onBatchSuccess (response );
296
310
} finally {
297
311
onBatchCompletion ();
@@ -301,7 +315,9 @@ public void onSuccess(ResponseT response) {
301
315
@ Override
302
316
public void onFailure (Throwable throwable ) {
303
317
try {
304
- flowController .release (accumulatedBatch .elementCounter , accumulatedBatch .byteCounter );
318
+ flowController .release (
319
+ accumulatedBatch .resource .getElementCount (),
320
+ accumulatedBatch .resource .getByteCount ());
305
321
accumulatedBatch .onBatchFailure (throwable );
306
322
} finally {
307
323
onBatchCompletion ();
@@ -412,35 +428,31 @@ private static class Batch<ElementT, ElementResultT, RequestT, ResponseT> {
412
428
private final BatchingRequestBuilder <ElementT , RequestT > builder ;
413
429
private final List <BatchEntry <ElementT , ElementResultT >> entries ;
414
430
private final BatchingDescriptor <ElementT , ElementResultT , RequestT , ResponseT > descriptor ;
415
- private final BatcherStats batcherStats ;
416
- private final long elementThreshold ;
417
- private final long bytesThreshold ;
418
431
419
- private long elementCounter = 0 ;
420
- private long byteCounter = 0 ;
432
+ private final BatcherStats batcherStats ;
421
433
private long totalThrottledTimeMs = 0 ;
434
+ private BatchResource resource ;
422
435
423
436
private Batch (
424
437
RequestT prototype ,
425
438
BatchingDescriptor <ElementT , ElementResultT , RequestT , ResponseT > descriptor ,
426
- BatchingSettings batchingSettings ,
427
439
BatcherStats batcherStats ) {
428
440
this .descriptor = descriptor ;
429
441
this .builder = descriptor .newRequestBuilder (prototype );
430
442
this .entries = new ArrayList <>();
431
- Long elementCountThreshold = batchingSettings .getElementCountThreshold ();
432
- this .elementThreshold = elementCountThreshold == null ? 0 : elementCountThreshold ;
433
- Long requestByteThreshold = batchingSettings .getRequestByteThreshold ();
434
- this .bytesThreshold = requestByteThreshold == null ? 0 : requestByteThreshold ;
435
443
this .batcherStats = batcherStats ;
444
+ this .resource = descriptor .createEmptyResource ();
436
445
}
437
446
438
- 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 ) {
439
452
builder .add (element );
440
453
entries .add (BatchEntry .create (element , result ));
441
- elementCounter ++;
442
- byteCounter += descriptor .countBytes (element );
443
454
totalThrottledTimeMs += throttledTimeMs ;
455
+ resource = resource .add (newResource );
444
456
}
445
457
446
458
void onBatchSuccess (ResponseT response ) {
@@ -464,11 +476,7 @@ void onBatchFailure(Throwable throwable) {
464
476
}
465
477
466
478
boolean isEmpty () {
467
- return elementCounter == 0 ;
468
- }
469
-
470
- boolean hasAnyThresholdReached () {
471
- return elementCounter >= elementThreshold || byteCounter >= bytesThreshold ;
479
+ return resource .isEmpty ();
472
480
}
473
481
}
474
482
0 commit comments