/* * Copyright 2014, Tuplejump Inc. * * 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.tuplejump.stargate.cassandra; import com.tuplejump.stargate.Fields; import com.tuplejump.stargate.lucene.query.function.Tuple; import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.db.*; import org.apache.cassandra.db.composites.*; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * User: satya */ public class TableMapper { public final AbstractType primaryKeyAbstractType; public final AbstractType clusteringKeyType; public final CompositeType primaryKeyType; public final CellNameType clusteringCType; public final ColumnFamilyStore table; public final ByteBuffer defaultPartitionKey; public final boolean isMetaColumn; public final ColumnDefinition primaryColumnDefinition; public final CFMetaData cfMetaData; public TableMapper(ColumnFamilyStore table, boolean isMetaColumn, ColumnDefinition primaryColumnDefinition) { this.table = table; this.cfMetaData = table.metadata; this.clusteringCType = table.getComparator(); this.primaryKeyAbstractType = table.metadata.getKeyValidator(); this.clusteringKeyType = table.getComparator().asAbstractType(); this.primaryKeyType = CompositeType.getInstance(primaryKeyAbstractType, clusteringKeyType); this.defaultPartitionKey = defaultPartitionKey(); this.isMetaColumn = isMetaColumn; this.primaryColumnDefinition = primaryColumnDefinition; } public String primaryColumnName() { return primaryColumnDefinition.name.toString(); } public DecoratedKey decorateKey(ByteBuffer rowKey) { return table.partitioner.decorateKey(rowKey); } public void load(Map<String, Integer> positions, Tuple tuple, Row row) { ColumnFamily cf = row.cf; ByteBuffer rowKey = row.key.getKey(); Collection<Cell> cols = cf.getSortedColumns(); boolean keyColumnsAdded = false; for (Cell column : cols) { if (!keyColumnsAdded) { addKeyColumns(positions, tuple, rowKey); keyColumnsAdded = true; } String actualColumnName = column.name().cql3ColumnName(table.metadata).toString(); ByteBuffer colValue = column.value(); AbstractType<?> valueValidator = table.metadata.getValueValidator(column.name()); if (valueValidator.isCollection()) { CollectionType validator = (CollectionType) valueValidator; AbstractType keyType = validator.nameComparator(); AbstractType valueType = validator.valueComparator(); ByteBuffer keyBuf = column.name().collectionElement(); if (valueValidator instanceof MapType) { actualColumnName = actualColumnName + "." + keyType.compose(keyBuf); valueValidator = valueType; } else if (valueValidator instanceof SetType) { colValue = keyBuf; valueValidator = keyType; } else { valueValidator = valueType; } } for (String field : positions.keySet()) { if (actualColumnName.equalsIgnoreCase(field)) { tuple.getTuple()[positions.get(field)] = valueValidator.compose(colValue); } } } } private void addKeyColumns(Map<String, Integer> positions, Tuple tuple, ByteBuffer rowKey) { CType keyCType = table.metadata.getKeyValidatorAsCType(); Composite compoundRowKey = keyCType.fromByteBuffer(rowKey); List<ColumnDefinition> partitionKeys = table.metadata.partitionKeyColumns(); for (ColumnDefinition entry : partitionKeys) { ByteBuffer value = compoundRowKey.get(entry.position()); String actualColumnName = entry.name.toString(); for (String field : positions.keySet()) { if (actualColumnName.equalsIgnoreCase(field)) { tuple.getTuple()[positions.get(field)] = entry.type.compose(value); } } } } public Row getRowWithMetaColumn(ByteBuffer metaColumnValue) { if (isMetaColumn) { ColumnFamily cleanColumnFamily = ArrayBackedSortedColumns.factory.create(table.metadata); CellNameType cellNameType = table.getComparator(); boolean hasCollections = cellNameType.hasCollections(); int prefixSize = cellNameType.size() - (hasCollections ? 2 : 1); CBuilder builder = cellNameType.builder(); for (int i = 0; i < prefixSize; i++) { AbstractType<?> type = cellNameType.subtype(i); builder.add(Fields.defaultValue(type)); } Composite prefix = builder.build(); Iterable<ColumnDefinition> cols = table.metadata.regularAndStaticColumns(); for (ColumnDefinition columnDef : cols) { if (columnDef.equals(primaryColumnDefinition)) { addColumn(table, cleanColumnFamily, primaryColumnDefinition, prefix, metaColumnValue); } else { addColumn(table, cleanColumnFamily, columnDef, prefix, Fields.defaultValue(columnDef.type)); } } DecoratedKey dk = table.partitioner.decorateKey(defaultPartitionKey); return new Row(dk, cleanColumnFamily); } else { return null; } } private static void addColumn(ColumnFamilyStore table, ColumnFamily cleanColumnFamily, ColumnDefinition columnDefinition, Composite prefix, ByteBuffer metaColumnValue) { if (!columnDefinition.type.asCQL3Type().isCollection()) { CellNameType cellNameType = table.getComparator(); CellName cellName = cellNameType.create(prefix, columnDefinition); Cell scoreColumn = new BufferCell(cellName, metaColumnValue); cleanColumnFamily.addColumn(scoreColumn); } } private ByteBuffer defaultPartitionKey() { ByteBuffer partitionKey; AbstractType keyType = table.metadata.getKeyValidator(); if (keyType instanceof CompositeType) { CompositeType compositeType = ((CompositeType) keyType); CompositeType.Builder builder = compositeType.builder(); compositeType.getComponents(); for (AbstractType component : compositeType.getComponents()) { builder.add(Fields.defaultValue(component)); } partitionKey = builder.build(); } else { partitionKey = Fields.defaultValue(keyType); } return partitionKey; } public ByteBuffer primaryKey(ByteBuffer rowKey, CellName clusteringKey) { return primaryKeyType.builder().add(rowKey).add(clusteringKey.toByteBuffer()).build(); } public CellName extractClusteringKey(CellName cellName) { int clusterColumns = table.metadata.clusteringColumns().size(); Object[] components = new ByteBuffer[clusterColumns + 1]; for (int i = 0; i < clusterColumns; i++) { components[i] = cellName.get(i); } components[clusterColumns] = ByteBufferUtil.EMPTY_BYTE_BUFFER; return clusteringCType.makeCellName(components); } public CellName makeClusteringKey(ByteBuffer primaryKey) { ByteBuffer clusteringKeyBuf = primaryKeyType.extractLastComponent(primaryKey); return clusteringCType.cellFromByteBuffer(clusteringKeyBuf); } public final Map<CellName, ColumnFamily> getRows(ColumnFamily columnFamily) { Map<CellName, ColumnFamily> columnFamilies = new LinkedHashMap<>(); for (Cell cell : columnFamily) { CellName cellName = cell.name(); CellName clusteringKey = extractClusteringKey(cellName); ColumnFamily row = columnFamilies.get(clusteringKey); if (row == null) { row = ArrayBackedSortedColumns.factory.create(cfMetaData); columnFamilies.put(clusteringKey, row); } if (!isDroppedColumn(cell, cfMetaData)) { row.addColumn(cell); } } return columnFamilies; } public final Composite start(CellName cellName) { CBuilder builder = clusteringCType.builder(); for (int i = 0; i < cellName.clusteringSize(); i++) { ByteBuffer component = cellName.get(i); builder.add(component); } return builder.build(); } public final Composite end(Composite start) { return start.withEOC(Composite.EOC.END); } public boolean isDroppedColumn(Cell c, CFMetaData meta) { Long droppedAt = meta.getDroppedColumns().get(c.name().cql3ColumnName(meta)); return droppedAt != null && c.timestamp() <= droppedAt; } }