Gilad Chaplik has uploaded a new change for review.

Change subject: webadmin: Avoid duplicate server queries
......................................................................

webadmin: Avoid duplicate server queries

While executing several queries in parallel, the UI gets stuck;
There is a hard limitation of ~6 connections
for http requests (for the same host name).

We are getting a lot of performance issues that are related to it.
The main reproducer to 'UI not responding' is
re-sending a 'slow' query and run out of connections.

For a large scale env, this can be a serious problem;

In the patch:
When sending a second duplicate request from the same
place (model, queryType and parameters),
while the first request is waiting for response,
we will postpone it till the first is finished.
NOTE: we will postpone (save) only a single request, and avoid the others;
e.g., when pressing 30 time on a key in the GUI the first one will
be excuted and the others will pile up on the same place in the set.

Change-Id: I483a1c449f1eb2e9820464dbaf0a686f90923bb6
Signed-off-by: Gilad Chaplik <[email protected]>
---
M 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AsyncQuery.java
M 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java
2 files changed, 107 insertions(+), 33 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/54/9554/1

diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AsyncQuery.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AsyncQuery.java
index 2826dc4..1c2ffb1 100644
--- 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AsyncQuery.java
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AsyncQuery.java
@@ -3,6 +3,7 @@
 import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
 
 public class AsyncQuery {
+    private String queryKey;
     public Object Model;
     public INewAsyncCallback asyncCallback;
     public IAsyncConverter converterCallback;
@@ -82,4 +83,12 @@
     public IAsyncConverter getConverter() {
         return converterCallback;
     }
+
+    public String getQueryKey() {
+        return queryKey;
+    }
+
+    public void setQueryKey(String queryKey) {
+        this.queryKey = queryKey;
+    }
 }
diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java
index aa19f29..1b8a86e 100644
--- 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/Frontend.java
@@ -1,7 +1,9 @@
 package org.ovirt.engine.ui.frontend;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -39,6 +41,37 @@
 import com.google.gwt.user.client.rpc.StatusCodeException;
 
 public class Frontend {
+    static class QueryWrapper {
+        VdcQueryType queryType;
+        VdcQueryParametersBase parameters;
+        AsyncQuery callback;
+
+        public QueryWrapper(VdcQueryType queryType,
+                VdcQueryParametersBase parameters,
+                AsyncQuery callback) {
+            this.queryType = queryType;
+            this.parameters = parameters;
+            this.callback = callback;
+        }
+
+        public VdcQueryType getQueryType() {
+            return queryType;
+        }
+
+        public VdcQueryParametersBase getParameters() {
+            return parameters;
+        }
+
+        public AsyncQuery getCallback() {
+            return callback;
+        }
+
+        public String getKey() {
+            return queryType.toString() + parameters.getClass().toString() +
+                    callback.getModel().toString();
+        }
+    }
+
     private static final String RPC_TIMEOUT_EXCEPTION_STATUS_CODE_PREFIX = 
"120"; //$NON-NLS-1$
 
     private static Logger logger = Logger.getLogger(Frontend.class.getName());
@@ -48,6 +81,9 @@
             new ErrorTranslator((AppErrors) GWT.create(AppErrors.class));
     private static ErrorTranslator vdsmErrorsTranslator =
             new ErrorTranslator((VdsmErrors) GWT.create(VdsmErrors.class));
+
+    static Map<String, QueryWrapper> currentRequests = new HashMap<String, 
Frontend.QueryWrapper>();
+    static Map<String, QueryWrapper> pendingRequests = new HashMap<String, 
Frontend.QueryWrapper>();
 
     private static VdcQueryType[] subscribedQueryTypes;
 
@@ -131,59 +167,88 @@
     public static void RunQuery(final VdcQueryType queryType,
             final VdcQueryParametersBase parameters,
             final AsyncQuery callback) {
+        QueryWrapper queryWrapper = new QueryWrapper(queryType, parameters, 
callback);
+        callback.setQueryKey(queryWrapper.getKey());
+        if (currentRequests.get(callback.getQueryKey()) == null) {
+            currentRequests.put(callback.getQueryKey(), queryWrapper);
+        } else {
+            pendingRequests.put(callback.getQueryKey(), queryWrapper);
+            return;
+        }
+
         initQueryParamsFilter(parameters);
         dumpQueryDetails(queryType, parameters);
         logger.finer("Frontend: Invoking async runQuery."); //$NON-NLS-1$
         raiseQueryStartedEvent(queryType, callback.getContext());
-
         GenericApiGWTServiceAsync service = 
GenericApiGWTServiceAsync.Util.getInstance();
         service.RunQuery(queryType, parameters, new 
AsyncCallback<VdcQueryReturnValue>() {
             @Override
             public void onFailure(Throwable caught) {
-                if (ignoreFailure(caught)) {
-                    return;
+                try {
+                    if (ignoreFailure(caught)) {
+                        return;
+                    }
+                    logger.log(Level.SEVERE, "Failed to execute RunQuery: " + 
caught, caught); //$NON-NLS-1$
+                    getEventsHandler().runQueryFailed(null);
+                    failureEventHandler(caught);
+                    if (callback.isHandleFailure()) {
+                        callback.asyncCallback.OnSuccess(callback.getModel(), 
null);
+                    }
+                    raiseQueryCompleteEvent(queryType, callback.getContext());
+                } finally {
+                    QueryWrapper wrapper = 
pendingRequests.get(callback.getQueryKey());
+                    if (wrapper != null) {
+                        pendingRequests.remove(callback.getQueryKey());
+                        RunQuery(wrapper.getQueryType(), 
wrapper.getParameters(), wrapper.getCallback());
+                    } else {
+                        currentRequests.remove(callback.getQueryKey());
+                    }
                 }
-                logger.log(Level.SEVERE, "Failed to execute RunQuery: " + 
caught, caught); //$NON-NLS-1$
-                getEventsHandler().runQueryFailed(null);
-                failureEventHandler(caught);
-                if (callback.isHandleFailure()) {
-                    callback.asyncCallback.OnSuccess(callback.getModel(), 
null);
-                }
-                raiseQueryCompleteEvent(queryType, callback.getContext());
             }
 
             @Override
             public void onSuccess(VdcQueryReturnValue result) {
-                logger.finer("Succesful returned result from RunQuery."); 
//$NON-NLS-1$
+                try {
+                    logger.finer("Succesful returned result from RunQuery."); 
//$NON-NLS-1$
 
-                if (!result.getSucceeded()) {
-                    logger.log(Level.WARNING, "Failure while invoking 
ReturnQuery [" + result.getExceptionString() //$NON-NLS-1$
-                            + "]"); //$NON-NLS-1$
-                    if (getEventsHandler() != null) {
-                        ArrayList<VdcQueryReturnValue> failedResult = new 
ArrayList<VdcQueryReturnValue>();
-                        failedResult.add(result);
-                        // getEventsHandler().runQueryFailed(failedResult);
-                        String errorMessage = result.getExceptionString();
-                        handleNotLoggedInEvent(errorMessage);
+                    if (!result.getSucceeded()) {
+                        logger.log(Level.WARNING, "Failure while invoking 
ReturnQuery [" + result.getExceptionString() //$NON-NLS-1$
+                                + "]"); //$NON-NLS-1$
+                        if (getEventsHandler() != null) {
+                            ArrayList<VdcQueryReturnValue> failedResult = new 
ArrayList<VdcQueryReturnValue>();
+                            failedResult.add(result);
+                            // getEventsHandler().runQueryFailed(failedResult);
+                            String errorMessage = result.getExceptionString();
+                            handleNotLoggedInEvent(errorMessage);
+                            if (callback.isHandleFailure()) {
+                                
callback.getDel().OnSuccess(callback.getModel(), result);
+                            }
+                        }
                         if (callback.isHandleFailure()) {
                             callback.getDel().OnSuccess(callback.getModel(), 
result);
                         }
+                    } else {
+                        callback.setOriginalReturnValue(result);
+                        if (callback.getConverter() != null) {
+                            callback.getDel().OnSuccess(callback.getModel(),
+                                    
callback.getConverter().Convert(result.getReturnValue(), callback));
+                        }
+                        else {
+                            callback.getDel().OnSuccess(callback.getModel(), 
result);
+                        }
                     }
-                    if (callback.isHandleFailure()) {
-                        callback.getDel().OnSuccess(callback.getModel(), 
result);
-                    }
-                } else {
-                    callback.setOriginalReturnValue(result);
-                    if (callback.getConverter() != null) {
-                        callback.getDel().OnSuccess(callback.getModel(),
-                                
callback.getConverter().Convert(result.getReturnValue(), callback));
-                    }
-                    else {
-                        callback.getDel().OnSuccess(callback.getModel(), 
result);
+
+                    raiseQueryCompleteEvent(queryType, callback.getContext());
+                }
+                finally {
+                    QueryWrapper wrapper = 
pendingRequests.get(callback.getQueryKey());
+                    if (wrapper != null) {
+                        pendingRequests.remove(callback.getQueryKey());
+                        RunQuery(wrapper.getQueryType(), 
wrapper.getParameters(), wrapper.getCallback());
+                    } else {
+                        currentRequests.remove(callback.getQueryKey());
                     }
                 }
-
-                raiseQueryCompleteEvent(queryType, callback.getContext());
             }
         });
     }


--
To view, visit http://gerrit.ovirt.org/9554
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I483a1c449f1eb2e9820464dbaf0a686f90923bb6
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Gilad Chaplik <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to