-
Notifications
You must be signed in to change notification settings - Fork 581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added retry mechanism parameter for LongWriteOperation #357
Changes from 2 commits
1a49205
e752af4
d6f113e
ce02a02
f54f4ae
563e675
03effa5
8570954
f979bfa
d39f6ad
1026205
cdddd29
ef0bfe2
cf207e2
8d3f2fe
b9c0ba2
db06717
6dd6dd2
0635c28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.polidea.rxandroidble.internal.connection; | ||
|
||
import com.polidea.rxandroidble.RxBleConnection; | ||
|
||
public class NoRetryStrategy implements RxBleConnection.WriteOperationRetryStrategy { | ||
|
||
@Override | ||
public Boolean call(Integer integer, Throwable throwable) { | ||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
|
||
import com.polidea.rxandroidble.ClientComponent; | ||
import com.polidea.rxandroidble.RxBleConnection.WriteOperationAckStrategy; | ||
import com.polidea.rxandroidble.RxBleConnection.WriteOperationRetryStrategy; | ||
import com.polidea.rxandroidble.exceptions.BleDisconnectedException; | ||
import com.polidea.rxandroidble.exceptions.BleException; | ||
import com.polidea.rxandroidble.exceptions.BleGattCallbackTimeoutException; | ||
|
@@ -33,6 +34,7 @@ | |
import rx.functions.Action0; | ||
import rx.functions.Action1; | ||
import rx.functions.Func1; | ||
import rx.functions.Func2; | ||
|
||
public class CharacteristicLongWriteOperation extends QueueOperation<byte[]> { | ||
|
||
|
@@ -43,8 +45,10 @@ public class CharacteristicLongWriteOperation extends QueueOperation<byte[]> { | |
private final BluetoothGattCharacteristic bluetoothGattCharacteristic; | ||
private final PayloadSizeLimitProvider batchSizeProvider; | ||
private final WriteOperationAckStrategy writeOperationAckStrategy; | ||
private final WriteOperationRetryStrategy writeOperationRetryStrategy; | ||
private final byte[] bytesToWrite; | ||
private byte[] tempBatchArray; | ||
private int retryCounter; | ||
|
||
CharacteristicLongWriteOperation( | ||
BluetoothGatt bluetoothGatt, | ||
|
@@ -54,6 +58,7 @@ public class CharacteristicLongWriteOperation extends QueueOperation<byte[]> { | |
BluetoothGattCharacteristic bluetoothGattCharacteristic, | ||
PayloadSizeLimitProvider batchSizeProvider, | ||
WriteOperationAckStrategy writeOperationAckStrategy, | ||
WriteOperationRetryStrategy writeOperationRetryStrategy, | ||
byte[] bytesToWrite) { | ||
this.bluetoothGatt = bluetoothGatt; | ||
this.rxBleGattCallback = rxBleGattCallback; | ||
|
@@ -62,12 +67,14 @@ public class CharacteristicLongWriteOperation extends QueueOperation<byte[]> { | |
this.bluetoothGattCharacteristic = bluetoothGattCharacteristic; | ||
this.batchSizeProvider = batchSizeProvider; | ||
this.writeOperationAckStrategy = writeOperationAckStrategy; | ||
this.writeOperationRetryStrategy = writeOperationRetryStrategy; | ||
this.bytesToWrite = bytesToWrite; | ||
this.retryCounter = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not a big fan of variables that are changed as a side effect. This usually makes room for a mistake and makes the code harder to trace. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean we should not have a separated counter in this Operation class at all? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that Darek meant putting a reset in a |
||
} | ||
|
||
@Override | ||
protected void protectedRun(final Emitter<byte[]> emitter, final QueueReleaseInterface queueReleaseInterface) throws Throwable { | ||
int batchSize = batchSizeProvider.getPayloadSizeLimit(); | ||
final int batchSize = batchSizeProvider.getPayloadSizeLimit(); | ||
|
||
if (batchSize <= 0) { | ||
throw new IllegalArgumentException("batchSizeProvider value must be greater than zero (now: " + batchSize + ")"); | ||
|
@@ -87,9 +94,11 @@ protected void protectedRun(final Emitter<byte[]> emitter, final QueueReleaseInt | |
timeoutObservable, | ||
timeoutConfiguration.timeoutScheduler | ||
) | ||
.doOnNext(resetRetryCounter()) | ||
.repeatWhen(bufferIsNotEmptyAndOperationHasBeenAcknowledgedAndNotUnsubscribed( | ||
writeOperationAckStrategy, byteBuffer, emitterWrapper | ||
)) | ||
.retry(retryStrategy(byteBuffer, batchSize)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that we should go with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, that makes sense. |
||
.toCompletable() | ||
.subscribe( | ||
new Action0() { | ||
|
@@ -209,4 +218,30 @@ public Boolean call(Object emission) { | |
} | ||
}; | ||
} | ||
|
||
private Action1<ByteAssociation<UUID>> resetRetryCounter() { | ||
return new Action1<ByteAssociation<UUID>>() { | ||
@Override | ||
public void call(ByteAssociation<UUID> uuidByteAssociation) { | ||
retryCounter = 0; | ||
} | ||
}; | ||
} | ||
|
||
private Func2<Integer, Throwable, Boolean> retryStrategy(final ByteBuffer byteBuffer, final int batchSize) { | ||
return new Func2<Integer, Throwable, Boolean>() { | ||
@Override | ||
public Boolean call(Integer integer, Throwable throwable) { | ||
// Individual counter for each batch payload. | ||
retryCounter++; | ||
final Boolean retry = writeOperationRetryStrategy.call(retryCounter, throwable); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The biggest question here is to:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, probably we should go for
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're reading in my mind :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I came up with the following private static Func1<Observable<? extends Throwable>, Observable<?>> retryOperationStrategy(
final WriteOperationRetryStrategy writeOperationRetryStrategy,
final ByteBuffer byteBuffer,
final int batchSize) {
return new Func1<Observable<? extends Throwable>, Observable<?>>() {
@Override
public Observable<?> call(Observable<? extends Throwable> observable) {
return observable
.flatMap(applyRetryStrategy())
.map(replaceByteBufferPositionForRetry());
}
@NonNull
private Func1<Throwable, Observable<WriteOperationRetryStrategy.LongWriteFailure>> applyRetryStrategy() {
return new Func1<Throwable, Observable<WriteOperationRetryStrategy.LongWriteFailure>>() {
@Override
public Observable<WriteOperationRetryStrategy.LongWriteFailure> call(Throwable cause) {
if (!(cause instanceof BleException)) {
return Observable.error(cause);
}
final int failedBatchNumber = (byteBuffer.position() - batchSize) / batchSize;
final WriteOperationRetryStrategy.LongWriteFailure longWriteFailure =
new WriteOperationRetryStrategy.LongWriteFailure(failedBatchNumber, (BleException) cause);
return writeOperationRetryStrategy.call(Observable.just(longWriteFailure));
}
};
}
@NonNull
private Func1<WriteOperationRetryStrategy.LongWriteFailure, Object> replaceByteBufferPositionForRetry() {
return new Func1<WriteOperationRetryStrategy.LongWriteFailure, Object>() {
@Override
public Object call(WriteOperationRetryStrategy.LongWriteFailure longWriteFailure) {
final int newBufferPosition = longWriteFailure.getBatchNumber() * batchSize;
byteBuffer.position(newBufferPosition);
return longWriteFailure;
}
};
}
};
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you could push another commit to this PR I could then comment on specific lines There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, done! |
||
if (!retry) { | ||
return false; | ||
} | ||
// Reset buffer to last position | ||
byteBuffer.position(byteBuffer.position() - batchSize); | ||
return true; | ||
} | ||
}; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be placed near
WriteOperationAckStrategy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.