Skip to content

Commit

Permalink
Introduce TableLayout abstraction
Browse files Browse the repository at this point in the history
This commit introduces the concept of a TableLayout, which represents a physical
organization of a Table. A table can have multiple physical layouts with different
properties (partitioning, grouping, predicate, columns, etc).

Presto will be able to take advantage of this information to pick the layout
most suitable to satisfy a given query plan based on desired properties.

Partition/ConnectorPartition/etc. are now deprecated, but there's an adaptation
layer that allows existing connectors to work seamlessly with the new APIs. Once
all connectors are migrated, those APIs will be removed.
  • Loading branch information
martint committed Apr 15, 2015
1 parent c5a3bfc commit 72ce7a4
Show file tree
Hide file tree
Showing 50 changed files with 1,324 additions and 673 deletions.
Expand Up @@ -230,7 +230,7 @@ private synchronized void addConnector(String catalogName, String connectorId, C

metadataManager.addInformationSchemaMetadata(makeInformationSchemaConnectorId(connectorId), catalogName, new InformationSchemaMetadata(catalogName));
splitManager.addConnectorSplitManager(makeInformationSchemaConnectorId(connectorId), new InformationSchemaSplitManager(nodeManager));
pageSourceManager.addConnectorPageSourceProvider(makeInformationSchemaConnectorId(connectorId), new InformationSchemaPageSourceProvider(metadataManager, splitManager));
pageSourceManager.addConnectorPageSourceProvider(makeInformationSchemaConnectorId(connectorId), new InformationSchemaPageSourceProvider(metadataManager));

Connector systemConnector = new SystemConnector(nodeManager, systemTables);
metadataManager.addSystemTablesMetadata(makeSystemTablesConnectorId(connectorId), catalogName, systemConnector.getMetadata());
Expand Down
Expand Up @@ -19,28 +19,30 @@
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.metadata.OperatorNotFoundException;
import com.facebook.presto.metadata.ParametricFunction;
import com.facebook.presto.metadata.Partition;
import com.facebook.presto.metadata.PartitionResult;
import com.facebook.presto.metadata.QualifiedTableName;
import com.facebook.presto.metadata.QualifiedTablePrefix;
import com.facebook.presto.metadata.TableHandle;
import com.facebook.presto.metadata.TableLayout;
import com.facebook.presto.metadata.TableLayoutResult;
import com.facebook.presto.metadata.ViewDefinition;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.ColumnHandle;
import com.facebook.presto.spi.ConnectorPageSource;
import com.facebook.presto.spi.ConnectorPageSourceProvider;
import com.facebook.presto.spi.ConnectorSplit;
import com.facebook.presto.spi.Constraint;
import com.facebook.presto.spi.FixedPageSource;
import com.facebook.presto.spi.Page;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.SerializableNativeValue;
import com.facebook.presto.spi.TupleDomain;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.split.SplitManager;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import io.airlift.slice.Slice;

import javax.inject.Inject;
Expand Down Expand Up @@ -71,13 +73,11 @@ public class InformationSchemaPageSourceProvider
implements ConnectorPageSourceProvider
{
private final Metadata metadata;
private final SplitManager splitManager;

@Inject
public InformationSchemaPageSourceProvider(Metadata metadata, SplitManager splitManager)
public InformationSchemaPageSourceProvider(Metadata metadata)
{
this.metadata = checkNotNull(metadata, "metadata is null");
this.splitManager = checkNotNull(splitManager, "splitManager is null");
}

@Override
Expand Down Expand Up @@ -247,40 +247,47 @@ private InternalTable buildPartitions(Session session, String catalogName, Map<S
QualifiedTableName tableName = extractQualifiedTableName(catalogName, filters);

InternalTable.Builder table = InternalTable.builder(informationSchemaTableColumns(TABLE_INTERNAL_PARTITIONS));
int partitionNumber = 1;

Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName);
checkArgument(tableHandle.isPresent(), "Table %s does not exist", tableName);
Map<ColumnHandle, String> columnHandles = ImmutableBiMap.copyOf(metadata.getColumnHandles(tableHandle.get())).inverse();
PartitionResult partitionResult = splitManager.getPartitions(tableHandle.get(), Optional.empty());

for (Partition partition : partitionResult.getPartitions()) {
for (Entry<ColumnHandle, SerializableNativeValue> entry : partition.getTupleDomain().extractNullableFixedValues().entrySet()) {
ColumnHandle columnHandle = entry.getKey();
String columnName = columnHandles.get(columnHandle);
String value = null;
if (entry.getValue().getValue() != null) {
ColumnMetadata columnMetadata = metadata.getColumnMetadata(tableHandle.get(), columnHandle);
try {
FunctionInfo operator = metadata.getFunctionRegistry().getCoercion(columnMetadata.getType(), VARCHAR);
value = ((Slice) operator.getMethodHandle().invokeWithArguments(entry.getValue().getValue())).toStringUtf8();
}
catch (OperatorNotFoundException e) {
value = "<UNREPRESENTABLE VALUE>";
}
catch (Throwable throwable) {
throw Throwables.propagate(throwable);

List<TableLayoutResult> layouts = metadata.getLayouts(tableHandle.get(), Optional.empty(), Constraint.<ColumnHandle>alwaysTrue());

if (layouts.size() == 1) {
TableLayout layout = Iterables.getOnlyElement(layouts).getLayout();

layout.getDiscretePredicates().ifPresent(domains -> {
int partitionNumber = 1;
for (TupleDomain<ColumnHandle> domain : domains) {
for (Entry<ColumnHandle, SerializableNativeValue> entry : domain.extractNullableFixedValues().entrySet()) {
ColumnHandle columnHandle = entry.getKey();
String columnName = columnHandles.get(columnHandle);
String value = null;
if (entry.getValue().getValue() != null) {
ColumnMetadata columnMetadata = metadata.getColumnMetadata(tableHandle.get(), columnHandle);
try {
FunctionInfo operator = metadata.getFunctionRegistry().getCoercion(columnMetadata.getType(), VARCHAR);
value = ((Slice) operator.getMethodHandle().invokeWithArguments(entry.getValue().getValue())).toStringUtf8();
}
catch (OperatorNotFoundException e) {
value = "<UNREPRESENTABLE VALUE>";
}
catch (Throwable throwable) {
throw Throwables.propagate(throwable);
}
}
table.add(
catalogName,
tableName.getSchemaName(),
tableName.getTableName(),
partitionNumber,
columnName,
value);
}
partitionNumber++;
}
table.add(
catalogName,
tableName.getSchemaName(),
tableName.getTableName(),
partitionNumber,
columnName,
value);
}
partitionNumber++;
});
}
return table.build();
}
Expand Down
Expand Up @@ -30,6 +30,7 @@ public class HandleJsonModule
public void configure(Binder binder)
{
jsonBinder(binder).addModuleBinding().to(TableHandleJacksonModule.class);
jsonBinder(binder).addModuleBinding().to(TableLayoutHandleJacksonModule.class);
jsonBinder(binder).addModuleBinding().to(ColumnHandleJacksonModule.class);
jsonBinder(binder).addModuleBinding().to(SplitJacksonModule.class);
jsonBinder(binder).addModuleBinding().to(OutputTableHandleJacksonModule.class);
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.facebook.presto.spi.ConnectorOutputTableHandle;
import com.facebook.presto.spi.ConnectorSplit;
import com.facebook.presto.spi.ConnectorTableHandle;
import com.facebook.presto.spi.ConnectorTableLayoutHandle;

import javax.inject.Inject;

Expand Down Expand Up @@ -61,6 +62,26 @@ public String getId(ConnectorTableHandle tableHandle)
throw new IllegalArgumentException("No connector for table handle: " + tableHandle);
}

public String getId(ConnectorTableLayoutHandle handle)
{
if (handle instanceof LegacyTableLayoutHandle) {
LegacyTableLayoutHandle legacyHandle = (LegacyTableLayoutHandle) handle;
for (Entry<String, ConnectorHandleResolver> entry : handleIdResolvers.entrySet()) {
if (entry.getValue().canHandle(legacyHandle.getTable())) {
return entry.getKey();
}
}
}
else {
for (Entry<String, ConnectorHandleResolver> entry : handleIdResolvers.entrySet()) {
if (entry.getValue().canHandle(handle)) {
return entry.getKey();
}
}
}
throw new IllegalArgumentException("No connector for table handle: " + handle);
}

public String getId(ColumnHandle columnHandle)
{
for (Entry<String, ConnectorHandleResolver> entry : handleIdResolvers.entrySet()) {
Expand Down Expand Up @@ -116,6 +137,16 @@ public Class<? extends ConnectorTableHandle> getTableHandleClass(String id)
return resolverFor(id).getTableHandleClass();
}

public Class<? extends ConnectorTableLayoutHandle> getTableLayoutHandleClass(String id)
{
try {
return resolverFor(id).getTableLayoutHandleClass();
}
catch (UnsupportedOperationException e) {
return LegacyTableLayoutHandle.class;
}
}

public Class<? extends ColumnHandle> getColumnHandleClass(String id)
{
return resolverFor(id).getColumnHandleClass();
Expand Down
@@ -0,0 +1,85 @@
/*
* 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.
*/
package com.facebook.presto.metadata;

import com.facebook.presto.spi.ConnectorPartition;
import com.facebook.presto.spi.ConnectorTableHandle;
import com.facebook.presto.spi.ConnectorTableLayoutHandle;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
import java.util.Objects;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

// Adaptation layer for connectors that implement the old getPartitions and getPartitionSplits API
// TODO: remove once all connectors migrate to getTableLayouts/getSplits API
public final class LegacyTableLayoutHandle
implements ConnectorTableLayoutHandle
{
private final ConnectorTableHandle table;
private final List<ConnectorPartition> partitions;

@JsonCreator
public LegacyTableLayoutHandle(@JsonProperty("table") ConnectorTableHandle table)
{
requireNonNull(table, "table is null");

this.table = table;
this.partitions = null;
}

public LegacyTableLayoutHandle(ConnectorTableHandle table, List<ConnectorPartition> partitions)
{
requireNonNull(table, "table is null");
requireNonNull(partitions, "partitions is null");

this.table = table;
this.partitions = partitions;
}

@JsonProperty
public ConnectorTableHandle getTable()
{
return table;
}

public List<ConnectorPartition> getPartitions()
{
checkState(partitions != null, "Partitions dropped by serialization");
return partitions;
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LegacyTableLayoutHandle that = (LegacyTableLayoutHandle) o;
return Objects.equals(table, that.table) &&
Objects.equals(partitions, that.partitions);
}

@Override
public int hashCode()
{
return Objects.hash(table, partitions);
}
}
Expand Up @@ -16,6 +16,7 @@
import com.facebook.presto.Session;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.ColumnHandle;
import com.facebook.presto.spi.Constraint;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.spi.type.TypeSignature;
Expand All @@ -28,6 +29,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public interface Metadata
{
Expand Down Expand Up @@ -57,6 +59,12 @@ FunctionInfo resolveOperator(OperatorType operatorType, List<? extends Type> arg
@NotNull
Optional<TableHandle> getTableHandle(Session session, QualifiedTableName tableName);

@NotNull
List<TableLayoutResult> getLayouts(TableHandle tableHandle, Optional<Set<ColumnHandle>> requiredColumns, Constraint<ColumnHandle> constraint);

@NotNull
TableLayout getLayout(TableLayoutHandle handle);

/**
* Return the metadata for the specified table handle.
*
Expand Down

0 comments on commit 72ce7a4

Please sign in to comment.