use of org.apache.cassandra.schema.ColumnMetadata in project cassandra by apache.
the class Rows method merge.
/**
* Merges two rows into the given builder, mainly for merging memtable rows. In addition to reconciling the cells
* in each row, the liveness info, and deletion times for the row and complex columns are also merged.
* <p>
* Note that this method assumes that the provided rows can meaningfully be reconciled together. That is,
* that the rows share the same clustering value, and belong to the same partition.
*
* @param existing
* @param update
* @param builder the row build to which the result of the reconciliation is written.
* @param nowInSec the current time in seconds (which plays a role during reconciliation
* because deleted cells always have precedence on timestamp equality and deciding if a
* cell is a live or not depends on the current time due to expiring cells).
*
* @return the smallest timestamp delta between corresponding rows from existing and update. A
* timestamp delta being computed as the difference between the cells and DeletionTimes from {@code existing}
* and those in {@code existing}.
*/
public static long merge(Row existing, Row update, Row.Builder builder, int nowInSec) {
Clustering clustering = existing.clustering();
builder.newRow(clustering);
LivenessInfo existingInfo = existing.primaryKeyLivenessInfo();
LivenessInfo updateInfo = update.primaryKeyLivenessInfo();
LivenessInfo mergedInfo = existingInfo.supersedes(updateInfo) ? existingInfo : updateInfo;
long timeDelta = Math.abs(existingInfo.timestamp() - mergedInfo.timestamp());
Row.Deletion rowDeletion = existing.deletion().supersedes(update.deletion()) ? existing.deletion() : update.deletion();
if (rowDeletion.deletes(mergedInfo))
mergedInfo = LivenessInfo.EMPTY;
else if (rowDeletion.isShadowedBy(mergedInfo))
rowDeletion = Row.Deletion.LIVE;
builder.addPrimaryKeyLivenessInfo(mergedInfo);
builder.addRowDeletion(rowDeletion);
DeletionTime deletion = rowDeletion.time();
Iterator<ColumnData> a = existing.iterator();
Iterator<ColumnData> b = update.iterator();
ColumnData nexta = a.hasNext() ? a.next() : null, nextb = b.hasNext() ? b.next() : null;
while (nexta != null | nextb != null) {
int comparison = nexta == null ? 1 : nextb == null ? -1 : nexta.column.compareTo(nextb.column);
ColumnData cura = comparison <= 0 ? nexta : null;
ColumnData curb = comparison >= 0 ? nextb : null;
ColumnMetadata column = (cura != null ? cura : curb).column;
if (column.isSimple()) {
timeDelta = Math.min(timeDelta, Cells.reconcile((Cell) cura, (Cell) curb, deletion, builder, nowInSec));
} else {
ComplexColumnData existingData = (ComplexColumnData) cura;
ComplexColumnData updateData = (ComplexColumnData) curb;
DeletionTime existingDt = existingData == null ? DeletionTime.LIVE : existingData.complexDeletion();
DeletionTime updateDt = updateData == null ? DeletionTime.LIVE : updateData.complexDeletion();
DeletionTime maxDt = existingDt.supersedes(updateDt) ? existingDt : updateDt;
if (maxDt.supersedes(deletion))
builder.addComplexDeletion(column, maxDt);
else
maxDt = deletion;
Iterator<Cell> existingCells = existingData == null ? null : existingData.iterator();
Iterator<Cell> updateCells = updateData == null ? null : updateData.iterator();
timeDelta = Math.min(timeDelta, Cells.reconcileComplex(column, existingCells, updateCells, maxDt, builder, nowInSec));
}
if (cura != null)
nexta = a.hasNext() ? a.next() : null;
if (curb != null)
nextb = b.hasNext() ? b.next() : null;
}
return timeDelta;
}
use of org.apache.cassandra.schema.ColumnMetadata in project cassandra by apache.
the class ViewUpdateGenerator method createEntry.
/**
* Creates a view entry corresponding to the provided base row.
* <p>
* This method checks that the base row does match the view filter before applying it.
*/
private void createEntry(Row baseRow) {
// Before create a new entry, make sure it matches the view filter
if (!matchesViewFilter(baseRow))
return;
startNewUpdate(baseRow);
currentViewEntryBuilder.addPrimaryKeyLivenessInfo(computeLivenessInfoForEntry(baseRow));
currentViewEntryBuilder.addRowDeletion(baseRow.deletion());
for (ColumnData data : baseRow) {
ColumnMetadata viewColumn = view.getViewColumn(data.column());
// Alose, if it's part of the view PK it's already been taken into account in the clustering.
if (viewColumn == null || viewColumn.isPrimaryKeyColumn())
continue;
addColumnData(viewColumn, data);
}
submitUpdate();
}
use of org.apache.cassandra.schema.ColumnMetadata in project cassandra by apache.
the class ViewUpdateGenerator method updateAction.
/**
* Compute which type of action needs to be performed to the view for a base table row
* before and after an update.
*/
private UpdateAction updateAction(Row existingBaseRow, Row mergedBaseRow) {
// but if we have no update at all, we shouldn't get there.
assert !mergedBaseRow.isEmpty();
if (baseMetadata.isCompactTable()) {
Clustering clustering = mergedBaseRow.clustering();
for (int i = 0; i < clustering.size(); i++) {
if (clustering.get(i) == null)
return UpdateAction.NONE;
}
}
assert view.baseNonPKColumnsInViewPK.size() <= 1 : "We currently only support one base non-PK column in the view PK";
if (view.baseNonPKColumnsInViewPK.isEmpty()) {
// The view entry is necessarily the same pre and post update.
// Note that we allow existingBaseRow to be null and treat it as empty (see MultiViewUpdateBuilder.generateViewsMutations).
boolean existingHasLiveData = existingBaseRow != null && existingBaseRow.hasLiveData(nowInSec);
boolean mergedHasLiveData = mergedBaseRow.hasLiveData(nowInSec);
return existingHasLiveData ? (mergedHasLiveData ? UpdateAction.UPDATE_EXISTING : UpdateAction.DELETE_OLD) : (mergedHasLiveData ? UpdateAction.NEW_ENTRY : UpdateAction.NONE);
}
ColumnMetadata baseColumn = view.baseNonPKColumnsInViewPK.get(0);
assert !baseColumn.isComplex() : "A complex column couldn't be part of the view PK";
Cell before = existingBaseRow == null ? null : existingBaseRow.getCell(baseColumn);
Cell after = mergedBaseRow.getCell(baseColumn);
// If the update didn't modified this column, the cells will be the same object so it's worth checking
if (before == after)
return isLive(before) ? UpdateAction.UPDATE_EXISTING : UpdateAction.NONE;
if (!isLive(before))
return isLive(after) ? UpdateAction.NEW_ENTRY : UpdateAction.NONE;
if (!isLive(after))
return UpdateAction.DELETE_OLD;
return baseColumn.cellValueType().compare(before.value(), after.value()) == 0 ? UpdateAction.UPDATE_EXISTING : UpdateAction.SWITCH_ENTRY;
}
use of org.apache.cassandra.schema.ColumnMetadata in project cassandra by apache.
the class TargetParser method parse.
public static Pair<ColumnMetadata, IndexTarget.Type> parse(TableMetadata metadata, IndexMetadata indexDef) {
String target = indexDef.options.get("target");
assert target != null : String.format("No target definition found for index %s", indexDef.name);
Pair<ColumnMetadata, IndexTarget.Type> result = parse(metadata, target);
if (result == null)
throw new ConfigurationException(String.format("Unable to parse targets for index %s (%s)", indexDef.name, target));
return result;
}
use of org.apache.cassandra.schema.ColumnMetadata in project cassandra by apache.
the class CassandraIndex method setMetadata.
private void setMetadata(IndexMetadata indexDef) {
metadata = indexDef;
Pair<ColumnMetadata, IndexTarget.Type> target = TargetParser.parse(baseCfs.metadata(), indexDef);
functions = getFunctions(indexDef, target);
TableMetadataRef tableRef = TableMetadataRef.forOfflineTools(indexCfsMetadata(baseCfs.metadata(), indexDef));
indexCfs = ColumnFamilyStore.createColumnFamilyStore(baseCfs.keyspace, tableRef.name, tableRef, baseCfs.getTracker().loadsstables);
indexedColumn = target.left;
}
Aggregations