Rewrite remote oracle wrapper to reduce requests
Gerrit was sending a suggest request roughly for every key typed. On a slow connection (or a slow server) this behavior caused a lot of suggestion requests whose results were immediately useless when the next key was processed. Wrap the reviewer suggestion with RemoteSuggestOracle, which allows at most one remote query to execute at a time. Intermediate queries are discarded, reducing the number of remote calls made by the UI when the user is typing faster than the network+server can process. This somewhat improves suggestion experience for reviewers on a slow site. Typing "John D<enter>" is now more likely to complete to a person named "John Doe" rather than "John Alberts", which was being selected from a stale result based on the "John" suggestion list. Change-Id: I9bfaa2fe5bd92bbbf38c086f7c909761854d718d
This commit is contained in:
@@ -21,7 +21,7 @@ import com.google.gerrit.client.groups.GroupInfo;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
|
||||
import com.google.gerrit.client.ui.OnEditEnabler;
|
||||
import com.google.gerrit.client.ui.RPCSuggestOracle;
|
||||
import com.google.gerrit.client.ui.RemoteSuggestOracle;
|
||||
import com.google.gerrit.client.ui.SmallHeading;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
@@ -120,7 +120,7 @@ public class AccountGroupInfoScreen extends AccountGroupScreen {
|
||||
ownerTxtBox = new NpTextBox();
|
||||
ownerTxtBox.setVisibleLength(60);
|
||||
final AccountGroupSuggestOracle accountGroupOracle = new AccountGroupSuggestOracle();
|
||||
ownerTxt = new SuggestBox(new RPCSuggestOracle(
|
||||
ownerTxt = new SuggestBox(new RemoteSuggestOracle(
|
||||
accountGroupOracle), ownerTxtBox);
|
||||
ownerTxt.setStyleName(Gerrit.RESOURCES.css().groupOwnerTextBox());
|
||||
ownerPanel.add(ownerTxt);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package com.google.gerrit.client.admin;
|
||||
|
||||
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
|
||||
import com.google.gerrit.client.ui.RPCSuggestOracle;
|
||||
import com.google.gerrit.client.ui.RemoteSuggestOracle;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gwt.editor.client.LeafValueEditor;
|
||||
@@ -53,7 +53,7 @@ public class GroupReferenceBox extends Composite implements
|
||||
textBox = new NpTextBox();
|
||||
oracle = new AccountGroupSuggestOracle();
|
||||
suggestBox = new SuggestBox( //
|
||||
new RPCSuggestOracle(oracle), //
|
||||
new RemoteSuggestOracle(oracle), //
|
||||
textBox, //
|
||||
suggestions);
|
||||
initWidget(suggestBox);
|
||||
|
||||
@@ -25,9 +25,9 @@ import com.google.gerrit.client.ui.SuggestAfterTypingNCharsOracle;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.user.client.ui.SuggestOracle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** REST API based suggestion Oracle for reviewers. */
|
||||
@@ -35,17 +35,22 @@ public class ReviewerSuggestOracle extends SuggestAfterTypingNCharsOracle {
|
||||
private Change.Id changeId;
|
||||
|
||||
@Override
|
||||
protected void _onRequestSuggestions(final Request req, final Callback callback) {
|
||||
ChangeApi.suggestReviewers(changeId.get(), req.getQuery(),
|
||||
req.getLimit()).get(new GerritCallback<JsArray<SuggestReviewerInfo>>() {
|
||||
protected void _onRequestSuggestions(final Request req, final Callback cb) {
|
||||
ChangeApi.suggestReviewers(changeId.get(), req.getQuery(), req.getLimit())
|
||||
.get(new GerritCallback<JsArray<SuggestReviewerInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(JsArray<SuggestReviewerInfo> result) {
|
||||
final List<RestReviewerSuggestion> r =
|
||||
new ArrayList<>(result.length());
|
||||
for (final SuggestReviewerInfo reviewer : Natives.asList(result)) {
|
||||
List<RestReviewerSuggestion> r = new ArrayList<>(result.length());
|
||||
for (SuggestReviewerInfo reviewer : Natives.asList(result)) {
|
||||
r.add(new RestReviewerSuggestion(reviewer));
|
||||
}
|
||||
callback.onSuggestionsReady(req, new Response(r));
|
||||
cb.onSuggestionsReady(req, new Response(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable err) {
|
||||
List<Suggestion> r = Collections.emptyList();
|
||||
cb.onSuggestionsReady(req, new Response(r));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -54,7 +59,7 @@ public class ReviewerSuggestOracle extends SuggestAfterTypingNCharsOracle {
|
||||
this.changeId = changeId;
|
||||
}
|
||||
|
||||
private static class RestReviewerSuggestion implements SuggestOracle.Suggestion {
|
||||
private static class RestReviewerSuggestion implements Suggestion {
|
||||
private final SuggestReviewerInfo reviewer;
|
||||
|
||||
RestReviewerSuggestion(final SuggestReviewerInfo reviewer) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.client.rpc.NativeString;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.client.ui.HintTextBox;
|
||||
import com.google.gerrit.client.ui.RemoteSuggestOracle;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
@@ -82,7 +83,9 @@ public class Reviewers extends Composite {
|
||||
Reviewers() {
|
||||
reviewerSuggestOracle = new ReviewerSuggestOracle();
|
||||
nameTxtBox = new HintTextBox();
|
||||
suggestBox = new SuggestBox(reviewerSuggestOracle, nameTxtBox);
|
||||
suggestBox = new SuggestBox(
|
||||
new RemoteSuggestOracle(reviewerSuggestOracle),
|
||||
nameTxtBox);
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
nameTxtBox.setVisibleLength(55);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class AddMemberBox extends Composite {
|
||||
addPanel = new FlowPanel();
|
||||
addMember = new Button(buttonLabel);
|
||||
nameTxtBox = new HintTextBox();
|
||||
nameTxt = new SuggestBox(new RPCSuggestOracle(
|
||||
nameTxt = new SuggestBox(new RemoteSuggestOracle(
|
||||
suggestOracle), nameTxtBox);
|
||||
nameTxt.setStyleName(Gerrit.RESOURCES.css().addMemberTextBox());
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (C) 2010 The Android Open Source Project
|
||||
//
|
||||
// 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.google.gerrit.client.ui;
|
||||
|
||||
import com.google.gwt.user.client.ui.SuggestOracle;
|
||||
|
||||
/** This class will proxy SuggestOracle requests to another SuggestOracle
|
||||
* while keeping track of the latest request. Any repsonse that belongs
|
||||
* to a request which is not the latest request will be dropped to prevent
|
||||
* invalid deliveries.
|
||||
*/
|
||||
|
||||
public class RPCSuggestOracle extends SuggestOracle {
|
||||
|
||||
private SuggestOracle oracle;
|
||||
private SuggestOracle.Request request;
|
||||
private SuggestOracle.Callback callback;
|
||||
private SuggestOracle.Callback myCallback = new SuggestOracle.Callback() {
|
||||
@Override
|
||||
public void onSuggestionsReady(SuggestOracle.Request req,
|
||||
SuggestOracle.Response response) {
|
||||
if (request == req) {
|
||||
callback.onSuggestionsReady(req, response);
|
||||
request = null;
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public RPCSuggestOracle(SuggestOracle ora) {
|
||||
oracle = ora;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuggestions(SuggestOracle.Request req,
|
||||
SuggestOracle.Callback cb) {
|
||||
request = req;
|
||||
callback = cb;
|
||||
oracle.requestSuggestions(req, myCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplayStringHTML() {
|
||||
return oracle.isDisplayStringHTML();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2010 The Android Open Source Project
|
||||
//
|
||||
// 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.google.gerrit.client.ui;
|
||||
|
||||
import com.google.gwt.user.client.ui.SuggestOracle;
|
||||
|
||||
/**
|
||||
* Delegates to a slow SuggestOracle, such as a remote server API.
|
||||
* <p>
|
||||
* A response is only supplied to the UI if no requests were made after the
|
||||
* oracle begin that request.
|
||||
* <p>
|
||||
* When a request is made while the delegate is still processing a prior request
|
||||
* all intermediate requests are discarded and the most recent request is
|
||||
* queued. The pending request's response is discarded and the most recent
|
||||
* request is started.
|
||||
*/
|
||||
public class RemoteSuggestOracle extends SuggestOracle {
|
||||
private final SuggestOracle oracle;
|
||||
private Query query;
|
||||
|
||||
public RemoteSuggestOracle(SuggestOracle src) {
|
||||
oracle = src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuggestions(Request req, Callback cb) {
|
||||
Query q = new Query(req, cb);
|
||||
if (query == null) {
|
||||
q.start();
|
||||
}
|
||||
query = q;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplayStringHTML() {
|
||||
return oracle.isDisplayStringHTML();
|
||||
}
|
||||
|
||||
private class Query implements Callback {
|
||||
final Request request;
|
||||
final Callback callback;
|
||||
|
||||
Query(Request req, Callback cb) {
|
||||
request = req;
|
||||
callback = cb;
|
||||
}
|
||||
|
||||
void start() {
|
||||
oracle.requestSuggestions(request, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuggestionsReady(Request req, Response res) {
|
||||
if (query == this) {
|
||||
// No new request was started while this query was running.
|
||||
// Propose this request's response as the suggestions.
|
||||
query = null;
|
||||
callback.onSuggestionsReady(req, res);
|
||||
} else {
|
||||
// Another query came in while this one was running. Skip
|
||||
// this response and start the most recent query.
|
||||
query.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user