You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2016/02/26 09:28:29 UTC
kylin git commit: KYLIN-579 Unload Hive table from kylin
Repository: kylin
Updated Branches:
refs/heads/2.x-staging 6ee409ccc -> 2e1d2f6b6
KYLIN-579 Unload Hive table from kylin
Signed-off-by: wangxianbin1987 <wa...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/2e1d2f6b
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/2e1d2f6b
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/2e1d2f6b
Branch: refs/heads/2.x-staging
Commit: 2e1d2f6b62903b16b17bd2442e3456107dc0aa6a
Parents: 6ee409c
Author: wangxianbin1987 <wa...@gmail.com>
Authored: Thu Feb 25 19:22:34 2016 +0800
Committer: shaofengshi <sh...@apache.org>
Committed: Fri Feb 26 16:18:50 2016 +0800
----------------------------------------------------------------------
.../java/org/apache/kylin/cube/CubeManager.java | 2 +
.../apache/kylin/metadata/MetadataManager.java | 30 +++++++++
.../kylin/metadata/project/ProjectManager.java | 12 ++++
.../kylin/rest/controller/TableController.java | 59 ++++++++++++++++-
.../apache/kylin/rest/service/CubeService.java | 14 +++++
.../apache/kylin/rest/service/ModelService.java | 15 +++++
.../kylin/rest/service/ProjectService.java | 20 ++++++
.../source/hive/HiveSourceTableLoader.java | 6 ++
webapp/app/js/controllers/sourceMeta.js | 66 ++++++++++++++++++++
webapp/app/js/services/tables.js | 1 +
.../app/partials/tables/source_table_tree.html | 6 +-
webapp/app/partials/tables/table_unload.html | 33 ++++++++++
12 files changed, 259 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java
----------------------------------------------------------------------
diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java
index 84dd30a..4951ce6 100644
--- a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java
+++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java
@@ -46,7 +46,9 @@ import org.apache.kylin.metadata.MetadataManager;
import org.apache.kylin.metadata.model.SegmentStatusEnum;
import org.apache.kylin.metadata.model.TableDesc;
import org.apache.kylin.metadata.model.TblColRef;
+import org.apache.kylin.metadata.project.ProjectInstance;
import org.apache.kylin.metadata.project.ProjectManager;
+import org.apache.kylin.metadata.project.RealizationEntry;
import org.apache.kylin.metadata.realization.IRealization;
import org.apache.kylin.metadata.realization.IRealizationConstants;
import org.apache.kylin.metadata.realization.IRealizationProvider;
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
index 80ee8b3..9f2a934 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
@@ -197,6 +197,12 @@ public class MetadataManager {
srcTableMap.put(srcTable.getIdentity(), srcTable);
}
+ public void removeSourceTable(String tableIdentity) throws IOException {
+ String path = TableDesc.concatResourcePath(tableIdentity);
+ getStore().deleteResource(path);
+ srcTableMap.remove(tableIdentity);
+ }
+
private void init(KylinConfig config) throws IOException {
this.config = config;
this.srcTableMap = new CaseInsensitiveStringCache<TableDesc>(config, Broadcaster.TYPE.TABLE);
@@ -336,6 +342,24 @@ public class MetadataManager {
return new ArrayList<>(ret);
}
+ public boolean isTableInModel(String tableName, String projectName) throws IOException {
+ for(DataModelDesc modelDesc : getModels(projectName)) {
+ if(modelDesc.getAllTables().contains(tableName.toUpperCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isTableInAnyModel(String tableName) {
+ for(DataModelDesc modelDesc : getModels()) {
+ if(modelDesc.getAllTables().contains(tableName.toUpperCase())){
+ return true;
+ }
+ }
+ return false;
+ }
+
private void reloadAllDataModel() throws IOException {
ResourceStore store = getStore();
logger.debug("Reloading DataModel from folder " + store.getReadableResourcePath(ResourceStore.DATA_MODEL_DESC_RESOURCE_ROOT));
@@ -441,6 +465,12 @@ public class MetadataManager {
srcTableExdMap.put(tableId, tableExdProperties);
}
+ public void removeTableExd(String tableIdentity) throws IOException {
+ String path = TableDesc.concatExdResourcePath(tableIdentity);
+ getStore().deleteResource(path);
+ srcTableExdMap.remove(tableIdentity);
+ }
+
public String appendDBName(String table) {
if (table.indexOf(".") > 0)
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
index 45bbb1b..f73239c 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
@@ -286,6 +286,18 @@ public class ProjectManager {
return projectInstance;
}
+ public void removeTableDescFromProject(String tableIdentities, String projectName) throws IOException {
+ MetadataManager metaMgr = getMetadataManager();
+ ProjectInstance projectInstance = getProject(projectName);
+ TableDesc table = metaMgr.getTableDesc(tableIdentities);
+ if (table == null) {
+ throw new IllegalStateException("Cannot find table '" + table + "' in metadata manager");
+ }
+
+ projectInstance.removeTable(table.getIdentity());
+ updateProject(projectInstance);
+ }
+
public List<ProjectInstance> findProjects(RealizationType type, String realizationName) {
List<ProjectInstance> result = Lists.newArrayList();
for (ProjectInstance prj : projectMap.values()) {
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/server/src/main/java/org/apache/kylin/rest/controller/TableController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/TableController.java b/server/src/main/java/org/apache/kylin/rest/controller/TableController.java
index 39af7db..98e8d58 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/TableController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/TableController.java
@@ -21,6 +21,7 @@ package org.apache.kylin.rest.controller;
import java.io.IOException;
import java.util.*;
+import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.apache.kylin.common.KylinConfig;
import org.apache.kylin.common.util.JsonUtil;
@@ -33,6 +34,8 @@ import org.apache.kylin.rest.request.CardinalityRequest;
import org.apache.kylin.rest.request.StreamingRequest;
import org.apache.kylin.rest.response.TableDescResponse;
import org.apache.kylin.rest.service.CubeService;
+import org.apache.kylin.rest.service.ModelService;
+import org.apache.kylin.rest.service.ProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -55,6 +58,10 @@ public class TableController extends BasicController {
@Autowired
private CubeService cubeMgmtService;
+ @Autowired
+ private ProjectService projectService;
+ @Autowired
+ private ModelService modelService;
/**
* Get available table list of the input database
@@ -124,21 +131,67 @@ public class TableController extends BasicController {
cubeMgmtService.syncTableToProject(loaded, project);
Map<String, String[]> result = new HashMap<String, String[]>();
result.put("result.loaded", loaded);
- result.put("result.unloaded", new String[] {});
+ result.put("result.unloaded", new String[]{});
+ return result;
+ }
+
+ @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.DELETE })
+ @ResponseBody
+ public Map<String, String[]> unLoadHiveTables(@PathVariable String tables, @PathVariable String project) {
+ Set<String> unLoadSuccess = Sets.newHashSet();
+ Set<String> unLoadFail = Sets.newHashSet();
+ Map<String, String[]> result = new HashMap<String, String[]>();
+ for (String tableName : tables.split(",")) {
+ if (unLoadHiveTable(tableName, project)) {
+ unLoadSuccess.add(tableName);
+ } else {
+ unLoadFail.add(tableName);
+ }
+ }
+ result.put("result.unload.success", (String[]) unLoadSuccess.toArray(new String[unLoadSuccess.size()]));
+ result.put("result.unload.fail", (String[]) unLoadFail.toArray(new String[unLoadFail.size()]));
return result;
}
+ /**
+ * table may referenced by several projects, and kylin only keep one copy of meta for each table,
+ * that's why we have two if statement here.
+ * @param tableName
+ * @param project
+ * @return
+ */
+ private boolean unLoadHiveTable(String tableName, String project) {
+ boolean rtn= false;
+ try {
+ if (!modelService.isTableInModel(tableName, project)) {
+ cubeMgmtService.removeTableFromProject(tableName, project);
+ rtn = true;
+ }
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ if(!projectService.isTableInAnyProject(tableName) && !modelService.isTableInAnyModel(tableName)) {
+ try {
+ cubeMgmtService.unLoadHiveTable(tableName);
+ rtn = true;
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ rtn = false;
+ }
+ }
+ return rtn;
+ }
@RequestMapping(value = "/addStreamingSrc", method = { RequestMethod.POST })
@ResponseBody
public Map<String, String> addStreamingTable(@RequestBody StreamingRequest request) throws IOException {
Map<String, String> result = new HashMap<String, String>();
String project = request.getProject();
- TableDesc desc = JsonUtil.readValue(request.getTableData(),TableDesc.class);
+ TableDesc desc = JsonUtil.readValue(request.getTableData(), TableDesc.class);
desc.setUuid(UUID.randomUUID().toString());
MetadataManager metaMgr = MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
metaMgr.saveSourceTable(desc);
- cubeMgmtService.syncTableToProject(new String[]{desc.getName()},project);
+ cubeMgmtService.syncTableToProject(new String[]{desc.getName()}, project);
result.put("success","true");
return result;
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/CubeService.java b/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
index 5d2776f..0c57d00 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
@@ -557,10 +557,24 @@ public class CubeService extends BasicService {
}
@PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
+ public void unLoadHiveTable(String tableName) throws IOException {
+ String[] dbTableName = HadoopUtil.parseHiveTableName(tableName);
+ tableName = dbTableName[0] + "." + dbTableName[1];
+ HiveSourceTableLoader.unLoadHiveTable(tableName.toUpperCase());
+ }
+
+ @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
public void syncTableToProject(String[] tables, String project) throws IOException {
getProjectManager().addTableDescToProject(tables, project);
}
+ @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
+ public void removeTableFromProject(String tableName, String projectName) throws IOException {
+ String[] dbTableName = HadoopUtil.parseHiveTableName(tableName);
+ tableName = dbTableName[0] + "." + dbTableName[1];
+ getProjectManager().removeTableDescFromProject(tableName, projectName);
+ }
+
@PreAuthorize(Constant.ACCESS_HAS_ROLE_MODELER + " or " + Constant.ACCESS_HAS_ROLE_ADMIN)
public void calculateCardinalityIfNotPresent(String[] tables, String submitter) throws IOException {
MetadataManager metaMgr = getMetadataManager();
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
index 9dae312..9d8ccfb 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.kylin.cube.model.CubeDesc;
+import org.apache.kylin.engine.mr.HadoopUtil;
import org.apache.kylin.invertedindex.model.IIDesc;
import org.apache.kylin.metadata.model.DataModelDesc;
import org.apache.kylin.metadata.project.ProjectInstance;
@@ -128,4 +129,18 @@ public class ModelService extends BasicService {
accessService.clean(desc, true);
}
+
+ @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#desc, 'ADMINISTRATION') or hasPermission(#desc, 'MANAGEMENT')")
+ public boolean isTableInAnyModel(String tableName) {
+ String[] dbTableName = HadoopUtil.parseHiveTableName(tableName);
+ tableName = dbTableName[0] + "." + dbTableName[1];
+ return getMetadataManager().isTableInAnyModel(tableName);
+ }
+
+ @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#desc, 'ADMINISTRATION') or hasPermission(#desc, 'MANAGEMENT')")
+ public boolean isTableInModel(String tableName, String projectName) throws IOException {
+ String[] dbTableName = HadoopUtil.parseHiveTableName(tableName);
+ tableName = dbTableName[0] + "." + dbTableName[1];
+ return getMetadataManager().isTableInModel(tableName, projectName);
+ }
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/server/src/main/java/org/apache/kylin/rest/service/ProjectService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/ProjectService.java b/server/src/main/java/org/apache/kylin/rest/service/ProjectService.java
index be70534..ad5a982 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/ProjectService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/ProjectService.java
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List;
import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.metadata.project.ProjectManager;
import org.apache.kylin.rest.constant.Constant;
import org.apache.kylin.rest.exception.InternalErrorException;
import org.apache.kylin.rest.request.CreateProjectRequest;
@@ -104,4 +105,23 @@ public class ProjectService extends BasicService {
accessService.clean(project, true);
}
+ public boolean isTableInAnyProject(String tableName) {
+ for(ProjectInstance projectInstance : ProjectManager.getInstance(getConfig()).listAllProjects()) {
+ if(projectInstance.containsTable(tableName.toUpperCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isTableInProject(String tableName, String projectName) {
+ ProjectInstance projectInstance = ProjectManager.getInstance(getConfig()).getProject(projectName);
+ if(projectInstance != null) {
+ if(projectInstance.containsTable(tableName.toUpperCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/source-hive/src/main/java/org/apache/kylin/source/hive/HiveSourceTableLoader.java
----------------------------------------------------------------------
diff --git a/source-hive/src/main/java/org/apache/kylin/source/hive/HiveSourceTableLoader.java b/source-hive/src/main/java/org/apache/kylin/source/hive/HiveSourceTableLoader.java
index bc722b3..f2f2d2a 100644
--- a/source-hive/src/main/java/org/apache/kylin/source/hive/HiveSourceTableLoader.java
+++ b/source-hive/src/main/java/org/apache/kylin/source/hive/HiveSourceTableLoader.java
@@ -78,6 +78,12 @@ public class HiveSourceTableLoader {
return loadedTables;
}
+ public static void unLoadHiveTable(String hiveTable) throws IOException {
+ MetadataManager metaMgr = MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
+ metaMgr.removeSourceTable(hiveTable);
+ metaMgr.removeTableExd(hiveTable);
+ }
+
private static List<String> extractHiveTables(String database, Set<String> tables, KylinConfig config) throws IOException {
List<String> loadedTables = Lists.newArrayList();
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/webapp/app/js/controllers/sourceMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js
index abdeeb8..cbd9f52 100755
--- a/webapp/app/js/controllers/sourceMeta.js
+++ b/webapp/app/js/controllers/sourceMeta.js
@@ -100,6 +100,25 @@ KylinApp
});
};
+ $scope.openUnLoadModal = function () {
+ $modal.open({
+ templateUrl: 'removeHiveTable.html',
+ controller: ModalInstanceCtrl,
+ backdrop : 'static',
+ resolve: {
+ tableNames: function () {
+ return $scope.tableNames;
+ },
+ projectName: function () {
+ return $scope.projectModel.selectedProject;
+ },
+ scope: function () {
+ return $scope;
+ }
+ }
+ });
+ };
+
var ModalInstanceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope) {
$scope.tableNames = "";
$scope.projectName = projectName;
@@ -152,6 +171,53 @@ KylinApp
loadingRequest.hide();
})
}
+
+ $scope.remove = function () {
+ if ($scope.tableNames.trim() === "") {
+ SweetAlert.swal('', 'Please input table(s) you want to synchronize.', 'info');
+ return;
+ }
+
+ if (!$scope.projectName) {
+ SweetAlert.swal('', 'Please choose your project first!.', 'info');
+ return;
+ }
+
+ $scope.cancel();
+ loadingRequest.show();
+ TableService.unLoadHiveTable({tableName: $scope.tableNames, action: projectName}, {}, function (result) {
+ var removedTableInfo = "";
+ angular.forEach(result['result.unload.success'], function (table) {
+ removedTableInfo += "\n" + table;
+ })
+ var unRemovedTableInfo = "";
+ angular.forEach(result['result.unload.fail'], function (table) {
+ unRemovedTableInfo += "\n" + table;
+ })
+
+ if (result['result.unload.fail'].length != 0 && result['result.unload.success'].length == 0) {
+ SweetAlert.swal('Failed!', 'Failed to synchronize following table(s): ' + unRemovedTableInfo, 'error');
+ }
+ if (result['result.unload.success'].length != 0 && result['result.unload.fail'].length == 0) {
+ SweetAlert.swal('Success!', 'The following table(s) have been successfully synchronized: ' + removedTableInfo, 'success');
+ }
+ if (result['result.unload.success'].length != 0 && result['result.unload.fail'].length != 0) {
+ SweetAlert.swal('Partial unloaded!', 'The following table(s) have been successfully synchronized: ' + removedTableInfo + "\n\n Failed to synchronize following table(s):" + unRemovedTableInfo, 'warning');
+ }
+ loadingRequest.hide();
+ scope.aceSrcTbLoaded(true);
+
+ }, function (e) {
+ if (e.data && e.data.exception) {
+ var message = e.data.exception;
+ var msg = !!(message) ? message : 'Failed to take action.';
+ SweetAlert.swal('Oops...', msg, 'error');
+ } else {
+ SweetAlert.swal('Oops...', "Failed to take action.", 'error');
+ }
+ loadingRequest.hide();
+ })
+ }
};
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/webapp/app/js/services/tables.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/tables.js b/webapp/app/js/services/tables.js
index 3b5e9f4..ca7fc42 100755
--- a/webapp/app/js/services/tables.js
+++ b/webapp/app/js/services/tables.js
@@ -23,6 +23,7 @@ KylinApp.factory('TableService', ['$resource', function ($resource, config) {
getExd: {method: 'GET', params: {action: 'exd-map'}, isArray: false},
reload: {method: 'PUT', params: {action: 'reload'}, isArray: false},
loadHiveTable: {method: 'POST', params: {}, isArray: false},
+ unLoadHiveTable: {method: 'DELETE', params: {}, isArray: false},
addStreamingSrc: {method: 'POST', params: {action:'addStreamingSrc'}, isArray: false},
genCardinality: {method: 'PUT', params: {action: 'cardinality'}, isArray: false}
});
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/webapp/app/partials/tables/source_table_tree.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/source_table_tree.html b/webapp/app/partials/tables/source_table_tree.html
index 767eb43..4eddc4f 100755
--- a/webapp/app/partials/tables/source_table_tree.html
+++ b/webapp/app/partials/tables/source_table_tree.html
@@ -25,8 +25,9 @@
<!--button-->
<div class="col-xs-5" style="padding-left: 0px;margin-top: 20px;">
<div class="pull-right">
- <a class="btn btn-xs btn-primary" tooltip="Load Hive Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openModal()"><i class="fa fa-download"></i></a>
- <a class="btn btn-xs btn-primary" tooltip="Add Streaming Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openStreamingSourceModal()"><i class="fa fa-area-chart"></i></a>
+ <a class="btn btn-xs btn-primary" tooltip="Load Hive Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openModal()"><i class="fa fa-download"></i></a>
+ <a class="btn btn-xs btn-info" tooltip="UnLoad Hive Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openUnLoadModal()"><i class="fa fa-remove"></i></a>
+ <a class="btn btn-xs btn-primary" tooltip="Add Streaming Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openStreamingSourceModal()"><i class="fa fa-area-chart"></i></a>
</div>
</div>
@@ -47,3 +48,4 @@
</div>
<div ng-include="'partials/tables/table_load.html'"></div>
+<div ng-include="'partials/tables/table_unload.html'"></div>
http://git-wip-us.apache.org/repos/asf/kylin/blob/2e1d2f6b/webapp/app/partials/tables/table_unload.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/table_unload.html b/webapp/app/partials/tables/table_unload.html
new file mode 100644
index 0000000..a1fcf6f
--- /dev/null
+++ b/webapp/app/partials/tables/table_unload.html
@@ -0,0 +1,33 @@
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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.
+-->
+
+ <script type="text/ng-template" id="removeHiveTable.html">
+ <div class="modal-header">
+ <h4>UnLoad Hive Table Metadata</h4>
+ </div>
+ <div class="modal-body">
+ <span><strong>Project: </strong>{{ $parent.projectName!=null?$parent.projectName:'NULL'}}</span>
+ <label for="tables"> Table Names:(Seperate with comma)</label>
+ <textarea ng-model="$parent.tableNames" class="form-control" id="tables"
+ placeholder="table1,table2 By default,system will choose 'Default' as database,you can specify database like this 'database.table'"></textarea>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary" ng-click="remove()">Sync</button>
+ <button class="btn btn-primary" ng-click="cancel()">Cancel</button>
+ </div>
+ </script>