You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by lu...@apache.org on 2021/07/18 23:15:24 UTC

[drill] branch master updated: DRILL-7922: Add feature of viewing external profile in web UI (#2225)

This is an automated email from the ASF dual-hosted git repository.

luoc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git


The following commit(s) were added to refs/heads/master by this push:
     new d71864a  DRILL-7922: Add feature of viewing external profile in web UI (#2225)
d71864a is described below

commit d71864a3d40b54c1f28926dc0d8d5ba1ea37298f
Author: feiteng <32...@qq.com>
AuthorDate: Thu Jul 8 23:37:13 2021 +0800

    DRILL-7922: Add feature of viewing external profile in web UI (#2225)
---
 .../exec/server/rest/profile/ProfileResources.java | 38 +++++++++++++++++++++-
 .../src/main/resources/rest/profile/list.ftl       | 13 ++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/ProfileResources.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/ProfileResources.java
index 1cdc359..b5e77b3 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/ProfileResources.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/ProfileResources.java
@@ -28,7 +28,9 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.security.RolesAllowed;
 import javax.inject.Inject;
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -57,11 +59,14 @@ import org.apache.drill.exec.store.sys.PersistentStore;
 import org.apache.drill.exec.store.sys.PersistentStoreProvider;
 import org.apache.drill.exec.work.WorkManager;
 import org.apache.drill.exec.work.foreman.Foreman;
+import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.glassfish.jersey.server.mvc.Viewable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.drill.shaded.guava.com.google.common.base.Joiner;
 import org.apache.drill.shaded.guava.com.google.common.collect.Lists;
+import org.apache.drill.shaded.guava.com.google.common.cache.Cache;
+import org.apache.drill.shaded.guava.com.google.common.cache.CacheBuilder;
 
 @Path("/")
 @RolesAllowed(DrillUserPrincipal.AUTHENTICATED_ROLE)
@@ -244,6 +249,9 @@ public class ProfileResources {
   //max Param to cap listing of profiles
   private static final String MAX_QPROFILES_PARAM = "max";
 
+  private static final Cache<String, String> PROFILE_CACHE = CacheBuilder
+    .newBuilder().expireAfterAccess(1, TimeUnit.MINUTES).build();
+
   @GET
   @Path("/profiles.json")
   @Produces(MediaType.APPLICATION_JSON)
@@ -375,7 +383,14 @@ public class ProfileResources {
   @Produces(MediaType.APPLICATION_JSON)
   public String getProfileJSON(@PathParam("queryid") String queryId) {
     try {
-      return new String(work.getContext().getProfileStoreContext().getProfileStoreConfig().getSerializer().serialize(getQueryProfile(queryId)));
+      String profileData = PROFILE_CACHE.getIfPresent(queryId);
+      if (profileData == null) {
+        return new String(work.getContext().getProfileStoreContext()
+          .getProfileStoreConfig().getSerializer().serialize(getQueryProfile(queryId)));
+      } else {
+        PROFILE_CACHE.invalidate(queryId);
+        return profileData;
+      }
     } catch (Exception e) {
       logger.debug("Failed to serialize profile for: " + queryId);
       return ("{ 'message' : 'error (unable to serialize profile)' }");
@@ -395,6 +410,27 @@ public class ProfileResources {
     }
   }
 
+  @POST
+  @Path("/profiles/view")
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  @Produces(MediaType.TEXT_HTML)
+  public Viewable viewProfile(@FormDataParam("profileData") String content) {
+    try {
+      QueryProfile profile = work.getContext().getProfileStoreContext()
+        .getProfileStoreConfig().getSerializer().deserialize(content.getBytes());
+      PROFILE_CACHE.put(profile.getQueryId(), content);
+      ProfileWrapper wrapper = new ProfileWrapper(profile,
+        work.getContext().getConfig(), request);
+      return ViewableWithPermissions.create(authEnabled.get(),
+        "/rest/profile/profile.ftl", sc, wrapper);
+    } catch (Exception | Error e) {
+      logger.error("Exception was thrown when parsing profile {} :\n{}",
+        content, e);
+      return ViewableWithPermissions.create(authEnabled.get(),
+        "/rest/errorMessage.ftl", sc, e);
+    }
+  }
+
   @GET
   @Path("/profiles/cancel/{queryid}")
   @Produces(MediaType.TEXT_PLAIN)
diff --git a/exec/java-exec/src/main/resources/rest/profile/list.ftl b/exec/java-exec/src/main/resources/rest/profile/list.ftl
index 58c86a4..5f4fd6c 100644
--- a/exec/java-exec/src/main/resources/rest/profile/list.ftl
+++ b/exec/java-exec/src/main/resources/rest/profile/list.ftl
@@ -84,6 +84,14 @@
         $("#queryCancelModal").modal("show");
     }
 
+    //Trigger the click event of file input and submit the file selected to the server
+    function viewProfile() {
+        $("#view-profile-file").change(function() {
+            $("#view-profile").submit();
+            this.value = null;
+        });
+        $("#view-profile-file").trigger("click");
+    }
 </script>
 
 <!-- CSS to control DataTable Elements -->
@@ -173,6 +181,11 @@
         <input id="fetchMax" type="text" size="5" name="max" value="" style="text-align: right" />
         <input type="submit" value="Reload"/>
       </form></td>
+      <td align="right" width="1px">
+        <form id="view-profile" action="/profiles/view" enctype='multipart/form-data' method="post">
+        <input type="file" id="view-profile-file" name="profileData" style="display: none"/>
+        <input type="button" value="View" onclick = "viewProfile()"/>
+      </form></td>
     </tr></table>
     <!-- Placed after textbox to allow for DOM to contain "fetchMax" element -->
     <script type="text/javascript" language="javascript">