Package io.crate.executor.transport.task

Source Code of io.crate.executor.transport.task.CreateTableTask$CreateTableResponseListener

/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements.  See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.  Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/

package io.crate.executor.transport.task;

import com.google.common.base.Joiner;
import io.crate.Constants;
import io.crate.PartitionName;
import io.crate.exceptions.Exceptions;
import io.crate.exceptions.TaskExecutionException;
import io.crate.executor.TaskResult;
import io.crate.planner.node.ddl.CreateTableNode;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.delete.TransportDeleteIndexAction;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.action.admin.indices.template.put.TransportPutIndexTemplateAction;
import org.elasticsearch.cluster.ClusterService;

import java.util.List;
import java.util.Locale;

public class CreateTableTask extends AbstractChainedTask {

    private static final TaskResult SUCCESS_RESULT = TaskResult.ONE_ROW;

    private final ClusterService clusterService;
    private final TransportCreateIndexAction createIndexAction;
    private final TransportDeleteIndexAction deleteIndexAction;
    private final TransportPutIndexTemplateAction putIndexTemplateAction;
    private final CreateTableNode planNode;

    public CreateTableTask(ClusterService clusterService,
                           TransportCreateIndexAction createIndexAction,
                           TransportDeleteIndexAction deleteIndexAction, TransportPutIndexTemplateAction putIndexTemplateAction,
                           CreateTableNode node) {
        this.clusterService = clusterService;
        this.createIndexAction = createIndexAction;
        this.deleteIndexAction = deleteIndexAction;
        this.putIndexTemplateAction = putIndexTemplateAction;
        this.planNode = node;
    }

    @Override
    protected void doStart(List<TaskResult> upstreamResults) {
        // real work done in createTable()
        deleteOrphans(new CreateTableResponseListener());
    }

    private CreateIndexRequest createIndexRequest() {
        return new CreateIndexRequest(planNode.tableName(), planNode.settings())
                .mapping(Constants.DEFAULT_MAPPING_TYPE, planNode.mapping());
    }

    private PutIndexTemplateRequest createTemplateRequest() {
        return new PutIndexTemplateRequest(planNode.templateName().get())
                .mapping(Constants.DEFAULT_MAPPING_TYPE, planNode.mapping())
                .create(true)
                .settings(planNode.settings())
                .template(planNode.templateIndexMatch().get())
                .alias(new Alias(planNode.tableName()));
    }

    private void createTable() {
        if (planNode.createsPartitionedTable()) {
            putIndexTemplateAction.execute(createTemplateRequest(), new ActionListener<PutIndexTemplateResponse>() {
                @Override
                public void onResponse(PutIndexTemplateResponse response) {
                    if (!response.isAcknowledged()) {
                        warnNotAcknowledged(String.format(Locale.ENGLISH, "creating table '%s'", planNode.tableName()));
                    }
                    result.set(SUCCESS_RESULT);
                }

                @Override
                public void onFailure(Throwable e) {
                    setException(e);
                }
            });
        } else {
            createIndexAction.execute(createIndexRequest(), new ActionListener<CreateIndexResponse>() {
                @Override
                public void onResponse(CreateIndexResponse response) {
                    if (!response.isAcknowledged()) {
                        warnNotAcknowledged(String.format(Locale.ENGLISH, "creating table '%s'", planNode.tableName()));
                    }
                    result.set(SUCCESS_RESULT);
                }

                @Override
                public void onFailure(Throwable e) {
                    setException(e);
                }
            });
        }
    }

    private void setException(Throwable e) {
        e = Exceptions.unwrap(e);
        String message = e.getMessage();
        if (message.equals("mapping [default]") && e.getCause() != null) {
            // this is a generic mapping parse exception,
            // the cause has usually a better more detailed error message
            result.setException(e.getCause());
        } else {
            result.setException(e);
        }
    }


    private void deleteOrphans(final CreateTableResponseListener listener) {
        if (clusterService.state().metaData().aliases().containsKey(planNode.tableName())
                && PartitionName.isPartition(
                clusterService.state().metaData().aliases().get(planNode.tableName()).keysIt().next(),
                planNode.tableName())
                ) {
            logger.debug("Deleting orphaned partitions with alias: {}", planNode.tableName());
            deleteIndexAction.execute(new DeleteIndexRequest(planNode.tableName()), new ActionListener<DeleteIndexResponse>() {
                @Override
                public void onResponse(DeleteIndexResponse response) {
                    if (!response.isAcknowledged()) {
                        warnNotAcknowledged("deleting orphaned alias");
                    }
                    deleteOrphanedPartitions(listener);
                }

                @Override
                public void onFailure(Throwable e) {
                    listener.onFailure(e);
                }
            });
        } else {
            deleteOrphanedPartitions(listener);
        }
    }

    /**
     * if some orphaned partition with the same table name still exist,
     * delete them beforehand as they would create unwanted and maybe invalid
     * initial data.
     *
     * should never delete partitions of existing partitioned tables
     */
    private void deleteOrphanedPartitions(final CreateTableResponseListener listener) {
        String partitionWildCard = PartitionName.templateName(planNode.tableName()) + "*";
        String[] orphans = clusterService.state().metaData().concreteIndices(
                new String[]{partitionWildCard});
        if (orphans.length > 0) {
            if (logger.isDebugEnabled()) {
                logger.debug("Deleting orphaned partitions: {}", Joiner.on(", ").join(orphans));
            }
            deleteIndexAction.execute(new DeleteIndexRequest(orphans), new ActionListener<DeleteIndexResponse>() {
                @Override
                public void onResponse(DeleteIndexResponse response) {
                    if (!response.isAcknowledged()) {
                        warnNotAcknowledged("deleting orphans");
                    }
                    listener.onResponse(null);
                }

                @Override
                public void onFailure(Throwable e) {
                    listener.onFailure(e);
                }
            });
        } else {
            listener.onResponse(null);
        }
    }

    class CreateTableResponseListener implements ActionListener<Void> {

        @Override
        public void onResponse(Void ignored) {
            createTable();
        }

        @Override
        public void onFailure(Throwable e) {
            throw new TaskExecutionException(CreateTableTask.this, e);
        }
    }

}
TOP

Related Classes of io.crate.executor.transport.task.CreateTableTask$CreateTableResponseListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.