/**
* 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.metadata.consensus;
import org.diqube.consensus.ConsensusMethod;
import org.diqube.consensus.ConsensusStateMachine;
import org.diqube.consensus.ConsensusUtil;
import org.diqube.name.FlattenedTableNameUtil;
import org.diqube.thrift.base.thrift.TableMetadata;
import org.diqube.util.Pair;
import io.atomix.copycat.Command;
import io.atomix.copycat.Query;
import io.atomix.copycat.server.Commit;
/**
* Consensus state machine that manages {@link TableMetadata}.
*
* TODO support removing table metadata and use it in a meaningful way - remove metadata only if table is removed across
* whole cluster.
*
* @author Bastian Gloeckle
*/
@ConsensusStateMachine
public interface TableMetadataStateMachine {
/**
* Compare a specific version of metadata is still valid and then set the metadata to a new value.
*
* @return true on success, false otherwise.
*/
@ConsensusMethod(dataClass = CompareAndSetTableMetadata.class)
public boolean compareAndSetTableMetadata(Commit<CompareAndSetTableMetadata> commit);
/**
* Return the currently valid TableMetadata and its version number.
*
* Note that the table name that can be searched for typically has to be a "valid table name", meaning either a normal
* table name, or, if its for a flattened table, then one created by {@link FlattenedTableNameUtil} (including the
* flattenId).
*
* @return <code>null</code> if not available. Note that also {@link Pair#getLeft()} can be null, but have a version
* number (in case the metadata is up for recomputation currently.
*/
@ConsensusMethod(dataClass = GetTableMetadata.class,
additionalSerializationClasses = { Pair.class, TableMetadata.class })
public Pair<TableMetadata, Long> getTableMetadata(Commit<GetTableMetadata> commit);
/**
* Enforces all nodes who participate in the consensus cluster to recompute their TableMetadata and call
* {@link #compareAndSetTableMetadata(Commit)} accordingly. This will only accept table names where there is metadata
* available of currently.
*/
@ConsensusMethod(dataClass = RecomputeTableMetadata.class)
public void recomputeTableMetadata(Commit<RecomputeTableMetadata> commit);
public static class CompareAndSetTableMetadata implements Command<Boolean> {
private static final long serialVersionUID = 1L;
private long previousMetadataVersion;
private TableMetadata newMetadata;
public long getPreviousMetadataVersion() {
return previousMetadataVersion;
}
public TableMetadata getNewMetadata() {
return newMetadata;
}
/**
* @param previousMetadataVersion
* Use {@link Long#MIN_VALUE} if expected that there is no entry at all.
*/
public static Commit<CompareAndSetTableMetadata> local(long previousMetadataVersion, TableMetadata newMetadata) {
CompareAndSetTableMetadata res = new CompareAndSetTableMetadata();
res.previousMetadataVersion = previousMetadataVersion;
res.newMetadata = newMetadata;
return ConsensusUtil.localCommit(res);
}
}
public static class GetTableMetadata implements Query<Pair<TableMetadata, Long>> {
private static final long serialVersionUID = 1L;
private String table;
public String getTable() {
return table;
}
@Override
public ConsistencyLevel consistency() {
return ConsistencyLevel.BOUNDED_LINEARIZABLE;
}
public static Commit<GetTableMetadata> local(String table) {
GetTableMetadata res = new GetTableMetadata();
res.table = table;
return ConsensusUtil.localCommit(res);
}
}
public static class RecomputeTableMetadata implements Command<Void> {
private static final long serialVersionUID = 1L;
private String tableName;
public String getTableName() {
return tableName;
}
public static Commit<RecomputeTableMetadata> local(String tableName) {
RecomputeTableMetadata res = new RecomputeTableMetadata();
res.tableName = tableName;
return ConsensusUtil.localCommit(res);
}
}
}