package com.splout.db.hadoop; /* * #%L * Splout SQL Hadoop library * %% * Copyright (C) 2012 Datasalt Systems S.L. * %% * Licensed 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. * #L% */ import com.datasalt.pangool.io.Schema.Field; import com.splout.db.engine.SploutEngine; import java.util.*; /** * This class is the main entry point for generating Splout views. Here we will use a Builder for adding the mapping * between a set of files in a FileSystem and the tables that we want to view in a Tablespace in Splout. * <p/> * We need to use {@link TableBuilder} for obtaining {@link Table} beans. Then we can add Tables to the Tablespace. * <p/> * We will obtain a {@link TablespaceSpec} bean after building it. */ // Still in development public class TablespaceBuilder { // When not specifying a number of partitions, a table is partitioned using all the partitions of the Splout cluster public final static int ALL_PARTITIONS_AVAILABLE = -1; // In-memory incremental builder state private List<Table> partitionedTables = new ArrayList<Table>(); private List<Table> replicatedTables = new ArrayList<Table>(); // Init statements that will be executed when opening the database private String[] initStatements = null; // How to partition the Tablespace private int nPartitions = -1; private SploutEngine engine = SploutEngine.getDefault(); /** * Add a new table to the builder - use a string table identifier for this. The method will return a bean that we can * use for filling the information of the table. * * @throws TablespaceBuilderException */ public TablespaceBuilder add(Table table) throws TablespaceBuilderException { if (table.getTableSpec().getPartitionFields() == null && table.getTableSpec().getPartitionByJavaScript() == null) { replicatedTables.add(table); } else { partitionedTables.add(table); } return this; } public void initStatements(String... initStatements) { this.initStatements = initStatements; } public void setNPartitions(int nPartitions) { this.nPartitions = nPartitions; } public void setEngine(SploutEngine engine) throws TablespaceBuilderException { setEngineClassName(engine.getClass().getName()); } public void setEngineClassName(String engineClass) throws TablespaceBuilderException { try { this.engine = Class.forName(engineClass).asSubclass(SploutEngine.class).newInstance(); } catch (InstantiationException e) { throw new TablespaceBuilderException("Engine class '" + engineClass + "' not instantiable."); } catch (IllegalAccessException e) { throw new TablespaceBuilderException("Engine class '" + engineClass + "' not instantiable."); } catch (ClassNotFoundException e) { throw new TablespaceBuilderException("Engine class '" + engineClass + "' not in classpath."); } } /** * Exception that is thrown if a Tablespace cannot be built because there is missing data or inconsistent data has * been specified. The reason is specified as the message of the Exception. */ @SuppressWarnings("serial") public static class TablespaceBuilderException extends Exception { public TablespaceBuilderException(String msg) { super(msg); } } /** * After specifying everything, call this method for building the final tablespace spec. */ public TablespaceSpec build() throws TablespaceBuilderException { if (nPartitions == -1) { throw new TablespaceBuilderException( "Can't create a Tablespace with #partitions = -1. Please set #partitions."); } Field[] partitionFields = null; if (partitionedTables.size() == 0) { throw new TablespaceBuilderException( "Can't create a Tablespace without any partitioned Table. At least one must be partitioned."); } Set<String> tableNames = new HashSet<String>(); List<String> tableNameList = new ArrayList<String>(); // Check that the partition field is coherent among different tables for (Table table : partitionedTables) { String tableName = table.getTableSpec().getSchema().getName(); tableNames.add(tableName); tableNameList.add(tableName); Field[] thisPartitionFields = table.getTableSpec().getPartitionFields(); if (partitionFields == null) { partitionFields = thisPartitionFields; } else { if (thisPartitionFields.length != partitionFields.length) { throw new TablespaceBuilderException("Different number of partition fields within tables: " + thisPartitionFields.length + ", " + partitionFields.length + " - must be the same for co-partitioning."); } for (int i = 0; i < thisPartitionFields.length; i++) { if (!thisPartitionFields[i].getType().equals(partitionFields[i].getType())) { throw new TablespaceBuilderException( "Partition fields " + thisPartitionFields[i] + ", " + partitionFields[i] + " are not of the same type. They must be the same type for tables to be co-partitioned."); } } } } for (Table table : replicatedTables) { String tableName = table.getTableSpec().getSchema().getName(); tableNames.add(tableName); tableNameList.add(tableName); } if (tableNames.size() != tableNameList.size()) { throw new TablespaceBuilderException( "There is collision between table names. Maybe you added the same name twice. Table names: " + tableNameList); } if (initStatements == null) { return new TablespaceSpec(partitionedTables, replicatedTables, nPartitions, null, engine); } else { return new TablespaceSpec(partitionedTables, replicatedTables, nPartitions, Arrays.asList(initStatements), engine); } } }