-
Notifications
You must be signed in to change notification settings - Fork 33
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
Propagate exceptions throughout transactions #367
Changes from all commits
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 |
---|---|---|
@@ -1 +1 @@ | ||
2.6.0 | ||
2.6.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,14 +68,14 @@ public Single<Res> single(Req.Builder request, boolean batch) { | |
ResponseCollector.Queue<Res> queue = resCollector.queue(requestID); | ||
if (batch) dispatcher.dispatch(req); | ||
else dispatcher.dispatchNow(req); | ||
return new Single<>(queue); | ||
return new Single<>(requestID, queue, this); | ||
} | ||
|
||
public Stream<ResPart> stream(Req.Builder request) { | ||
UUID requestID = UUID.randomUUID(); | ||
ResponseCollector.Queue<ResPart> collector = resPartCollector.queue(requestID); | ||
dispatcher.dispatch(request.setReqId(UUIDAsByteString(requestID)).build()); | ||
ResponsePartIterator iterator = new ResponsePartIterator(requestID, collector, dispatcher); | ||
ResponsePartIterator iterator = new ResponsePartIterator(requestID, collector, this); | ||
return StreamSupport.stream(spliteratorUnknownSize(iterator, ORDERED | IMMUTABLE), false); | ||
} | ||
|
||
|
@@ -118,22 +118,40 @@ private void close(@Nullable StatusRuntimeException error) { | |
} | ||
} | ||
|
||
public List<StatusRuntimeException> drainErrors() { | ||
List<StatusRuntimeException> errors = new ArrayList<>(resCollector.drainErrors()); | ||
errors.addAll(resPartCollector.drainErrors()); | ||
void singleDone(UUID requestID) { | ||
resCollector.remove(requestID); | ||
} | ||
|
||
void iteratorDone(UUID requestID) { | ||
resPartCollector.remove(requestID); | ||
Comment on lines
120
to
+126
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. separate methods for separate collectors 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. Just a fairly general comment, not limited to this change: How aligned are the implementations of tx exception propagation in the 3 clients? I'm pretty sure client-python had just one 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. yeah python has only one collector for all single and iterator, so it doesn't need split methods. I'm going to go back to update client-nodejs so it's in one of these two styles next (but won't release it) |
||
} | ||
|
||
public List<StatusRuntimeException> getErrors() { | ||
List<StatusRuntimeException> errors = new ArrayList<>(resCollector.getErrors()); | ||
errors.addAll(resPartCollector.getErrors()); | ||
return errors; | ||
} | ||
|
||
RequestTransmitter.Dispatcher dispatcher() { | ||
return dispatcher; | ||
} | ||
Comment on lines
+135
to
+137
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. we've replaced the |
||
|
||
public static class Single<T> { | ||
|
||
private final UUID requestID; | ||
private final BidirectionalStream stream; | ||
private final ResponseCollector.Queue<T> queue; | ||
|
||
public Single(ResponseCollector.Queue<T> queue) { | ||
public Single(UUID requestID, ResponseCollector.Queue<T> queue, BidirectionalStream stream) { | ||
this.requestID = requestID; | ||
this.queue = queue; | ||
this.stream = stream; | ||
} | ||
|
||
public T get() { | ||
return queue.take(); | ||
T value = queue.take(); | ||
stream.singleDone(requestID); | ||
return value; | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ | |
import java.util.concurrent.LinkedTransferQueue; | ||
|
||
import static com.vaticle.typedb.client.common.exception.ErrorMessage.Client.TRANSACTION_CLOSED; | ||
import static com.vaticle.typedb.client.common.exception.ErrorMessage.Client.TRANSACTION_CLOSED_WITH_ERRORS; | ||
import static com.vaticle.typedb.client.common.exception.ErrorMessage.Internal.UNEXPECTED_INTERRUPTION; | ||
|
||
public class ResponseCollector<R> { | ||
|
@@ -46,64 +47,63 @@ public ResponseCollector() { | |
collectors = new ConcurrentHashMap<>(); | ||
} | ||
|
||
public synchronized Queue<R> queue(UUID requestId) { | ||
synchronized Queue<R> queue(UUID requestId) { | ||
Queue<R> collector = new Queue<>(); | ||
collectors.put(requestId, collector); | ||
return collector; | ||
} | ||
|
||
public Queue<R> get(UUID requestId) { | ||
Queue<R> get(UUID requestId) { | ||
return collectors.get(requestId); | ||
} | ||
|
||
public synchronized void close(@Nullable StatusRuntimeException error) { | ||
void remove(UUID requestID) { | ||
this.collectors.remove(requestID); | ||
} | ||
|
||
synchronized void close(@Nullable StatusRuntimeException error) { | ||
collectors.values().forEach(collector -> collector.close(error)); | ||
} | ||
|
||
public List<StatusRuntimeException> drainErrors() { | ||
List<StatusRuntimeException> getErrors() { | ||
List<StatusRuntimeException> errors = new ArrayList<>(); | ||
collectors.values().forEach(collectors -> errors.addAll(collectors.drainErrors())); | ||
collectors.values().forEach(collector -> collector.getError().ifPresent(errors::add)); | ||
return errors; | ||
} | ||
|
||
public static class Queue<R> { | ||
|
||
private final BlockingQueue<Either<Response<R>, Done>> responseQueue; | ||
private StatusRuntimeException error; | ||
|
||
Queue() { | ||
// TODO: switch LinkedTransferQueue to LinkedBlockingQueue once issue #351 is fixed | ||
responseQueue = new LinkedTransferQueue<>(); | ||
error = null; | ||
} | ||
|
||
public R take() { | ||
try { | ||
Either<Response<R>, Done> response = responseQueue.take(); | ||
if (response.isFirst()) return response.first().message(); | ||
else if (!response.second().error().isPresent()) throw new TypeDBClientException(TRANSACTION_CLOSED); | ||
else throw TypeDBClientException.of(response.second().error().get()); | ||
else if (this.error != null) throw new TypeDBClientException(TRANSACTION_CLOSED_WITH_ERRORS, error); | ||
else throw new TypeDBClientException(TRANSACTION_CLOSED); | ||
} catch (InterruptedException e) { | ||
throw new TypeDBClientException(UNEXPECTED_INTERRUPTION); | ||
} | ||
} | ||
|
||
public List<StatusRuntimeException> drainErrors() { | ||
List<Either<Response<R>, Done>> messages = new ArrayList<>(); | ||
responseQueue.drainTo(messages); | ||
List<StatusRuntimeException> errors = new ArrayList<>(); | ||
messages.forEach(msg -> { | ||
if (msg.isSecond() && msg.second().error().isPresent()) { | ||
errors.add(msg.second().error().get()); | ||
} | ||
}); | ||
return errors; | ||
public Optional<StatusRuntimeException> getError() { | ||
return Optional.ofNullable(error); | ||
} | ||
|
||
public void put(R response) { | ||
responseQueue.add(Either.first(new Response<>(response))); | ||
} | ||
|
||
public void close(@Nullable StatusRuntimeException error) { | ||
responseQueue.add(Either.second(new Done(error))); | ||
this.error = error; | ||
responseQueue.add(Either.second(new Done())); | ||
Comment on lines
104
to
+106
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. hold on to error to be returned later like in node |
||
} | ||
|
||
private static class Response<R> { | ||
|
@@ -122,15 +122,7 @@ private R message() { | |
} | ||
|
||
private static class Done { | ||
@Nullable | ||
private final StatusRuntimeException error; | ||
|
||
private Done(StatusRuntimeException error) { | ||
this.error = error; | ||
} | ||
|
||
private Optional<StatusRuntimeException> error() { | ||
return Optional.ofNullable(error); | ||
private Done() { | ||
} | ||
} | ||
} | ||
|
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.
now add the stream to the iterator/Single so they can call back when they are finished in order to clean up