/**
* 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.data.table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.diqube.data.column.ColumnShard;
import org.diqube.data.column.StandardColumnShard;
import org.diqube.data.serialize.DataSerializable;
import org.diqube.data.serialize.DeserializationException;
import org.diqube.data.serialize.SerializationException;
import org.diqube.data.serialize.thrift.v1.SColumnShard;
import org.diqube.data.serialize.thrift.v1.STableShard;
import org.diqube.data.types.dbl.DoubleStandardColumnShard;
import org.diqube.data.types.lng.LongStandardColumnShard;
import org.diqube.data.types.str.StringStandardColumnShard;
import com.google.common.collect.Iterables;
/**
* Default implementation of {@link TableShard} for regular tables.
*
* @author Bastian Gloeckle
*/
@DataSerializable(thriftClass = STableShard.class)
public class DefaultTableShard implements TableShard {
private Map<String, StringStandardColumnShard> stringColumns = new HashMap<>();
private Map<String, DoubleStandardColumnShard> doubleColumns = new HashMap<>();
private Map<String, LongStandardColumnShard> longColumns = new HashMap<>();
private volatile Map<String, StandardColumnShard> allColumnsCache;
private Object allColumnsCacheSync = new Object();
private String tableName;
/** for deserialization only */
public DefaultTableShard() {
}
protected DefaultTableShard(String tableName, Collection<StandardColumnShard> columns) {
this.tableName = tableName;
for (ColumnShard col : columns) {
switch (col.getColumnType()) {
case STRING:
stringColumns.put(col.getName(), (StringStandardColumnShard) col);
break;
case LONG:
longColumns.put(col.getName(), (LongStandardColumnShard) col);
break;
case DOUBLE:
doubleColumns.put(col.getName(), (DoubleStandardColumnShard) col);
break;
}
}
}
@Override
public Map<String, StringStandardColumnShard> getStringColumns() {
return stringColumns;
}
@Override
public Map<String, DoubleStandardColumnShard> getDoubleColumns() {
return doubleColumns;
}
@Override
public Map<String, LongStandardColumnShard> getLongColumns() {
return longColumns;
}
@Override
public Map<String, StandardColumnShard> getColumns() {
if (allColumnsCache == null) {
synchronized (allColumnsCacheSync) {
if (allColumnsCache == null) {
Map<String, StandardColumnShard> res = new HashMap<>();
res.putAll(stringColumns);
res.putAll(longColumns);
res.putAll(doubleColumns);
allColumnsCache = res;
}
}
}
return allColumnsCache;
}
@Override
public long getNumberOfRowsInShard() {
if (stringColumns.size() > 0)
return stringColumns.values().iterator().next().getNumberOfRowsInColumnShard();
if (doubleColumns.size() > 0)
return doubleColumns.values().iterator().next().getNumberOfRowsInColumnShard();
if (longColumns.size() > 0)
return longColumns.values().iterator().next().getNumberOfRowsInColumnShard();
return 0;
}
@Override
public long getLowestRowId() {
if (stringColumns.size() > 0)
return stringColumns.values().iterator().next().getPages().firstKey();
if (doubleColumns.size() > 0)
return doubleColumns.values().iterator().next().getPages().firstKey();
if (longColumns.size() > 0)
return longColumns.values().iterator().next().getPages().firstKey();
return -1;
}
@Override
public void serialize(DataSerializationHelper mgr, STableShard target) throws SerializationException {
target.setTableName(tableName);
List<SColumnShard> serializedCols = new ArrayList<>();
for (StandardColumnShard shard : Iterables.concat(stringColumns.values(), longColumns.values(),
doubleColumns.values()))
serializedCols.add(mgr.serializeChild(SColumnShard.class, shard));
target.setColumnShards(serializedCols);
}
@Override
public void deserialize(DataSerializationHelper mgr, STableShard source) throws DeserializationException {
this.tableName = source.getTableName();
for (SColumnShard serCol : source.getColumnShards()) {
StandardColumnShard de = mgr.deserializeChild(StandardColumnShard.class, serCol);
if (de instanceof StringStandardColumnShard)
stringColumns.put(de.getName(), (StringStandardColumnShard) de);
else if (de instanceof LongStandardColumnShard)
longColumns.put(de.getName(), (LongStandardColumnShard) de);
else if (de instanceof DoubleStandardColumnShard)
doubleColumns.put(de.getName(), (DoubleStandardColumnShard) de);
else
throw new DeserializationException("Cannot deserialize column " + de.getName());
}
}
/** Only allowed to be called before the TableShard is registered in the TableRegistry! */
public void setTableName(String tableName) {
this.tableName = tableName;
}
@Override
public String getTableName() {
return tableName;
}
@Override
public long calculateApproximateSizeInBytes() {
long sumColNameLen = 0L;
long colSizes = 0L;
for (Entry<String, StringStandardColumnShard> shardEntry : stringColumns.entrySet()) {
sumColNameLen += shardEntry.getKey().length();
colSizes += shardEntry.getValue().calculateApproximateSizeInBytes();
}
for (Entry<String, DoubleStandardColumnShard> shardEntry : doubleColumns.entrySet()) {
sumColNameLen += shardEntry.getKey().length();
colSizes += shardEntry.getValue().calculateApproximateSizeInBytes();
}
for (Entry<String, LongStandardColumnShard> shardEntry : longColumns.entrySet()) {
sumColNameLen += shardEntry.getKey().length();
colSizes += shardEntry.getValue().calculateApproximateSizeInBytes();
}
return 16 + //
tableName.length() + //
colSizes + //
sumColNameLen;
}
}