/* * Licensed to 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.analyze; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.crate.exceptions.PartitionUnknownException; import io.crate.exceptions.ResourceUnknownException; import io.crate.executor.transport.RepositoryService; import io.crate.metadata.PartitionName; import io.crate.metadata.Schemas; import io.crate.metadata.TableIdent; import io.crate.metadata.doc.DocTableInfo; import io.crate.metadata.settings.SettingsApplier; import io.crate.metadata.settings.SettingsAppliers; import io.crate.metadata.table.Operation; import io.crate.metadata.table.SchemaInfo; import io.crate.metadata.table.TableInfo; import io.crate.sql.tree.CreateSnapshot; import io.crate.sql.tree.QualifiedName; import io.crate.sql.tree.Table; import org.apache.logging.log4j.Logger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; import java.util.*; import java.util.stream.Stream; import static io.crate.analyze.SnapshotSettings.IGNORE_UNAVAILABLE; import static io.crate.analyze.SnapshotSettings.WAIT_FOR_COMPLETION; class CreateSnapshotAnalyzer { private static final Logger LOGGER = Loggers.getLogger(CreateSnapshotAnalyzer.class); private final RepositoryService repositoryService; private final Schemas schemas; private static final ImmutableMap<String, SettingsApplier> SETTINGS = ImmutableMap.<String, SettingsApplier>builder() .put(IGNORE_UNAVAILABLE.name(), new SettingsAppliers.BooleanSettingsApplier(IGNORE_UNAVAILABLE)) .put(WAIT_FOR_COMPLETION.name(), new SettingsAppliers.BooleanSettingsApplier(WAIT_FOR_COMPLETION)) .build(); CreateSnapshotAnalyzer(RepositoryService repositoryService, Schemas schemas) { this.repositoryService = repositoryService; this.schemas = schemas; } public CreateSnapshotAnalyzedStatement analyze(CreateSnapshot node, Analysis analysis) { Optional<QualifiedName> repositoryName = node.name().getPrefix(); // validate repository Preconditions.checkArgument(repositoryName.isPresent(), "Snapshot must be specified by \"<repository_name>\".\"<snapshot_name>\""); Preconditions.checkArgument(repositoryName.get().getParts().size() == 1, String.format(Locale.ENGLISH, "Invalid repository name '%s'", repositoryName.get())); repositoryService.failIfRepositoryDoesNotExist(repositoryName.get().toString()); // snapshot existence in repo is validated upon execution String snapshotName = node.name().getSuffix(); Snapshot snapshot = new Snapshot(repositoryName.get().toString(), new SnapshotId(snapshotName, UUID.randomUUID().toString())); // validate and extract settings Settings settings = GenericPropertiesConverter.settingsFromProperties( node.properties(), analysis.parameterContext(), SETTINGS).build(); boolean ignoreUnavailable = settings.getAsBoolean(IGNORE_UNAVAILABLE.name(), IGNORE_UNAVAILABLE.defaultValue()); // iterate tables if (node.tableList().isPresent()) { List<Table> tableList = node.tableList().get(); Set<String> snapshotIndices = new HashSet<>(tableList.size()); for (Table table : tableList) { DocTableInfo docTableInfo; try { docTableInfo = schemas.getTableInfo( TableIdent.of(table, analysis.sessionContext().defaultSchema()), Operation.CREATE_SNAPSHOT); } catch (ResourceUnknownException e) { if (ignoreUnavailable) { LOGGER.info("ignoring: {}", e.getMessage()); continue; } else { throw e; } } if (table.partitionProperties().isEmpty()) { Stream.of(docTableInfo.concreteIndices()).forEach(snapshotIndices::add); } else { PartitionName partitionName = PartitionPropertiesAnalyzer.toPartitionName( docTableInfo, table.partitionProperties(), analysis.parameterContext().parameters() ); if (!docTableInfo.partitions().contains(partitionName)) { if (!ignoreUnavailable) { throw new PartitionUnknownException(docTableInfo.ident().fqn(), partitionName.ident()); } else { LOGGER.info("ignoring unknown partition of table '{}' with ident '{}'", partitionName.tableIdent(), partitionName.ident()); } } else { snapshotIndices.add(partitionName.asIndexName()); } } } return CreateSnapshotAnalyzedStatement.forTables(snapshot, settings, ImmutableList.copyOf(snapshotIndices)); } else { for (SchemaInfo schemaInfo : schemas) { for (TableInfo tableInfo : schemaInfo) { // only check for user generated tables if (tableInfo instanceof DocTableInfo) { Operation.blockedRaiseException(tableInfo, Operation.READ); } } } return CreateSnapshotAnalyzedStatement.all(snapshot, settings); } } }