/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.server.metadata;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import org.diqube.context.AutoInstatiate;
import org.diqube.data.table.Table;
import org.diqube.data.table.TableShard;
import org.diqube.executionenv.TableRegistry;
import org.diqube.metadata.TableMetadataManager;
import org.diqube.metadata.create.TableMetadataMerger;
import org.diqube.metadata.create.TableShardMetadataBuilderFactory;
import org.diqube.metadata.create.TableMetadataMerger.IllegalTableLayoutException;
import org.diqube.metadata.create.TableShardMetadataBuilder.IllegalTableShardLayoutException;
import org.diqube.thrift.base.thrift.TableMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class to publish the metadata of a all local {@link TableShard}s of a single table to the metadata cluster.
*
* @author Bastian Gloeckle
*/
@AutoInstatiate
public class ServerTableMetadataPublisher {
private static final Logger logger = LoggerFactory.getLogger(ServerTableMetadataPublisher.class);
@Inject
private TableRegistry tableRegistry;
@Inject
private TableShardMetadataBuilderFactory tableShardMetadataBuilderFactory;
@Inject
private TableMetadataManager tableMetadataManager;
/**
* Calculates and publishes the (local) metadata of the given table to the cluster by calling
* {@link TableMetadataManager#adjustTableMetadata(String, java.util.function.Function)} synchronously.
*
* @throws TableNotExistsException
* if table does not exist locally.
* @throws MergeImpossibleException
* If metadata cannot be merged.
*/
public void publishMetadataOfTable(String tableName) throws TableNotExistsException, MergeImpossibleException {
Table t = tableRegistry.getTable(tableName);
if (t == null)
throw new TableNotExistsException("Table '" + tableName + "' does not exist.");
Collection<TableShard> shards = t.getShards();
publishMetadataOfTableShards(tableName, shards);
}
/**
* Calculates and publishes metadata of the shards of a specfic local table to the cluster.
*
* @throws MergeImpossibleException
* If merge is impossible.
*/
public void publishMetadataOfTableShards(String tableName, Collection<TableShard> shards)
throws MergeImpossibleException {
List<TableMetadata> shardMetadata = new ArrayList<>();
TableMetadata localMerged;
try {
for (TableShard s : shards)
shardMetadata.add(tableShardMetadataBuilderFactory.createTableShardMetadataBuilder().from(s).build());
localMerged = new TableMetadataMerger().of(shardMetadata).merge();
} catch (IllegalTableShardLayoutException | IllegalTableLayoutException e) {
String msg = "While recomputing the table metadata of table '" + tableName + "' an error was encountered.";
logger.error(msg, e);
throw new MergeImpossibleException(msg, e);
}
MergeImpossibleException failure[] = new MergeImpossibleException[1];
failure[0] = null;
tableMetadataManager.adjustTableMetadata(tableName, oldMetadata -> {
if (oldMetadata == null)
return localMerged;
try {
return new TableMetadataMerger().of(localMerged, oldMetadata).merge();
} catch (Exception e) {
// could not merge our local results with the clusters'.
String msg = "While recomputing the table metadata of table '" + tableName + "' it was found that the "
+ "metadata of this node is incompatible with the metadata of the rest of the cluster.";
logger.error(msg, e);
failure[0] = new MergeImpossibleException(msg, e);
return oldMetadata;
}
});
if (failure[0] != null)
throw failure[0];
}
/* package */void setTableRegistry(TableRegistry tableRegistry) {
this.tableRegistry = tableRegistry;
}
/* package */void setTableShardMetadataBuilderFactory(
TableShardMetadataBuilderFactory tableShardMetadataBuilderFactory) {
this.tableShardMetadataBuilderFactory = tableShardMetadataBuilderFactory;
}
/* package */void setTableMetadataManager(TableMetadataManager tableMetadataManager) {
this.tableMetadataManager = tableMetadataManager;
}
public static class TableNotExistsException extends Exception {
private static final long serialVersionUID = 1L;
public TableNotExistsException(String msg) {
super(msg);
}
}
public static class MergeImpossibleException extends Exception {
private static final long serialVersionUID = 1L;
public MergeImpossibleException(String msg, Throwable t) {
super(msg, t);
}
}
}