use of org.apache.cassandra.schema.IndexMetadata in project cassandra by apache.
the class AlterTableStatement method announceMigration.
public Event.SchemaChange announceMigration(QueryState queryState, boolean isLocalOnly) throws RequestValidationException {
TableMetadata current = Schema.instance.validateTable(keyspace(), columnFamily());
if (current.isView())
throw new InvalidRequestException("Cannot use ALTER TABLE on Materialized View");
TableMetadata.Builder builder = current.unbuild();
ColumnIdentifier columnName = null;
ColumnMetadata def = null;
CQL3Type.Raw dataType = null;
boolean isStatic = false;
CQL3Type validator = null;
List<ViewMetadata> viewUpdates = new ArrayList<>();
Iterable<ViewMetadata> views = View.findAll(keyspace(), columnFamily());
switch(oType) {
case ALTER:
throw new InvalidRequestException("Altering of types is not allowed");
case ADD:
if (current.isDense())
throw new InvalidRequestException("Cannot add new column to a COMPACT STORAGE table");
for (AlterTableStatementColumn colData : colNameList) {
columnName = colData.getColumnName().getIdentifier(current);
def = builder.getColumn(columnName);
dataType = colData.getColumnType();
assert dataType != null;
isStatic = colData.getStaticType();
validator = dataType.prepare(keyspace());
if (isStatic) {
if (!current.isCompound())
throw new InvalidRequestException("Static columns are not allowed in COMPACT STORAGE tables");
if (current.clusteringColumns().isEmpty())
throw new InvalidRequestException("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
}
if (def != null) {
switch(def.kind) {
case PARTITION_KEY:
case CLUSTERING:
throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with a PRIMARY KEY part", columnName));
default:
throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with an existing column", columnName));
}
}
// Cannot re-add a dropped counter column. See #7831.
if (current.isCounter() && current.getDroppedColumn(columnName.bytes) != null)
throw new InvalidRequestException(String.format("Cannot re-add previously dropped counter column %s", columnName));
AbstractType<?> type = validator.getType();
if (type.isCollection() && type.isMultiCell()) {
if (!current.isCompound())
throw new InvalidRequestException("Cannot use non-frozen collections in COMPACT STORAGE tables");
if (current.isSuper())
throw new InvalidRequestException("Cannot use non-frozen collections with super column families");
// If there used to be a non-frozen collection column with the same name (that has been dropped),
// we could still have some data using the old type, and so we can't allow adding a collection
// with the same name unless the types are compatible (see #6276).
DroppedColumn dropped = current.droppedColumns.get(columnName.bytes);
if (dropped != null && dropped.column.type instanceof CollectionType && dropped.column.type.isMultiCell() && !type.isCompatibleWith(dropped.column.type)) {
String message = String.format("Cannot add a collection with the name %s because a collection with the same name" + " and a different type (%s) has already been used in the past", columnName, dropped.column.type.asCQL3Type());
throw new InvalidRequestException(message);
}
}
builder.addColumn(isStatic ? ColumnMetadata.staticColumn(current, columnName.bytes, type) : ColumnMetadata.regularColumn(current, columnName.bytes, type));
// as well
if (!isStatic)
for (ViewMetadata view : views) if (view.includeAllColumns)
viewUpdates.add(view.withAddedRegularColumn(ColumnMetadata.regularColumn(view.metadata, columnName.bytes, type)));
}
break;
case DROP:
if (!current.isCQLTable())
throw new InvalidRequestException("Cannot drop columns from a non-CQL3 table");
for (AlterTableStatementColumn colData : colNameList) {
columnName = colData.getColumnName().getIdentifier(current);
def = builder.getColumn(columnName);
if (def == null)
throw new InvalidRequestException(String.format("Column %s was not found in table %s", columnName, columnFamily()));
switch(def.kind) {
case PARTITION_KEY:
case CLUSTERING:
throw new InvalidRequestException(String.format("Cannot drop PRIMARY KEY part %s", columnName));
case REGULAR:
case STATIC:
builder.removeRegularOrStaticColumn(def.name);
builder.recordColumnDrop(def, deleteTimestamp == null ? queryState.getTimestamp() : deleteTimestamp);
break;
}
// If the dropped column is required by any secondary indexes
// we reject the operation, as the indexes must be dropped first
Indexes allIndexes = current.indexes;
if (!allIndexes.isEmpty()) {
ColumnFamilyStore store = Keyspace.openAndGetStore(current);
Set<IndexMetadata> dependentIndexes = store.indexManager.getDependentIndexes(def);
if (!dependentIndexes.isEmpty()) {
throw new InvalidRequestException(String.format("Cannot drop column %s because it has " + "dependent secondary indexes (%s)", def, dependentIndexes.stream().map(i -> i.name).collect(Collectors.joining(","))));
}
}
// If a column is dropped which is included in a view, we don't allow the drop to take place.
boolean rejectAlter = false;
StringBuilder viewNames = new StringBuilder();
for (ViewMetadata view : views) {
if (!view.includes(columnName))
continue;
if (rejectAlter)
viewNames.append(',');
rejectAlter = true;
viewNames.append(view.name);
}
if (rejectAlter)
throw new InvalidRequestException(String.format("Cannot drop column %s, depended on by materialized views (%s.{%s})", columnName.toString(), keyspace(), viewNames.toString()));
}
break;
case OPTS:
if (attrs == null)
throw new InvalidRequestException("ALTER TABLE WITH invoked, but no parameters found");
attrs.validate();
TableParams params = attrs.asAlteredTableParams(current.params);
if (!Iterables.isEmpty(views) && params.gcGraceSeconds == 0) {
throw new InvalidRequestException("Cannot alter gc_grace_seconds of the base table of a " + "materialized view to 0, since this value is used to TTL " + "undelivered updates. Setting gc_grace_seconds too low might " + "cause undelivered updates to expire " + "before being replayed.");
}
if (current.isCounter() && params.defaultTimeToLive > 0)
throw new InvalidRequestException("Cannot set default_time_to_live on a table with counters");
builder.params(params);
break;
case RENAME:
for (Map.Entry<ColumnMetadata.Raw, ColumnMetadata.Raw> entry : renames.entrySet()) {
ColumnIdentifier from = entry.getKey().getIdentifier(current);
ColumnIdentifier to = entry.getValue().getIdentifier(current);
def = current.getColumn(from);
if (def == null)
throw new InvalidRequestException(String.format("Cannot rename unknown column %s in table %s", from, current.name));
if (current.getColumn(to) != null)
throw new InvalidRequestException(String.format("Cannot rename column %s to %s in table %s; another column of that name already exist", from, to, current.name));
if (!def.isPrimaryKeyColumn())
throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", from));
if (!current.indexes.isEmpty()) {
ColumnFamilyStore store = Keyspace.openAndGetStore(current);
Set<IndexMetadata> dependentIndexes = store.indexManager.getDependentIndexes(def);
if (!dependentIndexes.isEmpty())
throw new InvalidRequestException(String.format("Cannot rename column %s because it has " + "dependent secondary indexes (%s)", from, dependentIndexes.stream().map(i -> i.name).collect(Collectors.joining(","))));
}
builder.renamePrimaryKeyColumn(from, to);
// If the view includes a renamed column, it must be renamed in the view table and the definition.
for (ViewMetadata view : views) {
if (!view.includes(from))
continue;
ColumnIdentifier viewFrom = entry.getKey().getIdentifier(view.metadata);
ColumnIdentifier viewTo = entry.getValue().getIdentifier(view.metadata);
viewUpdates.add(view.renamePrimaryKeyColumn(viewFrom, viewTo));
}
}
break;
}
// FIXME: Should really be a single announce for the table and views.
MigrationManager.announceTableUpdate(builder.build(), isLocalOnly);
for (ViewMetadata viewUpdate : viewUpdates) MigrationManager.announceViewUpdate(viewUpdate, isLocalOnly);
return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}
use of org.apache.cassandra.schema.IndexMetadata in project cassandra by apache.
the class PartitionRangeQueryPager method nextPageReadCommand.
protected ReadCommand nextPageReadCommand(int pageSize) throws RequestExecutionException {
DataLimits limits;
DataRange fullRange = ((PartitionRangeReadCommand) command).dataRange();
DataRange pageRange;
if (lastReturnedKey == null) {
pageRange = fullRange;
limits = command.limits().forPaging(pageSize);
} else {
// We want to include the last returned key only if we haven't achieved our per-partition limit, otherwise, don't bother.
boolean includeLastKey = remainingInPartition() > 0 && lastReturnedRow != null;
AbstractBounds<PartitionPosition> bounds = makeKeyBounds(lastReturnedKey, includeLastKey);
if (includeLastKey) {
pageRange = fullRange.forPaging(bounds, command.metadata().comparator, lastReturnedRow.clustering(command.metadata()), false);
limits = command.limits().forPaging(pageSize, lastReturnedKey.getKey(), remainingInPartition());
} else {
pageRange = fullRange.forSubRange(bounds);
limits = command.limits().forPaging(pageSize);
}
}
Index index = command.getIndex(Keyspace.openAndGetStore(command.metadata()));
Optional<IndexMetadata> indexMetadata = index != null ? Optional.of(index.getIndexMetadata()) : Optional.empty();
return new PartitionRangeReadCommand(command.metadata(), command.nowInSec(), command.columnFilter(), command.rowFilter(), limits, pageRange, indexMetadata);
}
use of org.apache.cassandra.schema.IndexMetadata in project spoon by INRIA.
the class SecondaryIndexManager method reload.
/**
* Drops and adds new indexes associated with the underlying CF
*/
public void reload() {
// figure out what needs to be added and dropped.
Indexes tableIndexes = baseCfs.metadata.getIndexes();
indexes.keySet().stream().filter(indexName -> !tableIndexes.has(indexName)).forEach(this::removeIndex);
// some may not have been created here yet, only added to schema
for (IndexMetadata tableIndex : tableIndexes) addIndex(tableIndex);
}
use of org.apache.cassandra.schema.IndexMetadata in project cassandra by apache.
the class SecondaryIndexTest method testIndexCreate.
@Test
public void testIndexCreate() throws IOException, InterruptedException, ExecutionException {
Keyspace keyspace = Keyspace.open(KEYSPACE1);
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(COMPOSITE_INDEX_TO_BE_ADDED);
// create a row and update the birthdate value, test that the index query fetches the new version
new RowUpdateBuilder(cfs.metadata(), 0, "k1").clustering("c").add("birthdate", 1L).build().applyUnsafe();
String indexName = "birthdate_index";
ColumnMetadata old = cfs.metadata().getColumn(ByteBufferUtil.bytes("birthdate"));
IndexMetadata indexDef = IndexMetadata.fromIndexTargets(Collections.singletonList(new IndexTarget(old.name, IndexTarget.Type.VALUES)), indexName, IndexMetadata.Kind.COMPOSITES, Collections.EMPTY_MAP);
TableMetadata current = cfs.metadata();
TableMetadata updated = current.unbuild().indexes(current.indexes.with(indexDef)).build();
MigrationManager.announceTableUpdate(updated, true);
// wait for the index to be built
Index index = cfs.indexManager.getIndex(indexDef);
do {
TimeUnit.MILLISECONDS.sleep(100);
} while (!cfs.indexManager.isIndexQueryable(index));
// we had a bug (CASSANDRA-2244) where index would get created but not flushed -- check for that
// the way we find the index cfs is a bit convoluted at the moment
ColumnFamilyStore indexCfs = cfs.indexManager.getIndex(indexDef).getBackingTable().orElseThrow(throwAssert("Index not found"));
assertFalse(indexCfs.getLiveSSTables().isEmpty());
assertIndexedOne(cfs, ByteBufferUtil.bytes("birthdate"), 1L);
// validate that drop clears it out & rebuild works (CASSANDRA-2320)
assertTrue(cfs.getBuiltIndexes().contains(indexName));
cfs.indexManager.removeIndex(indexDef.name);
assertFalse(cfs.getBuiltIndexes().contains(indexName));
// rebuild & re-query
Future future = cfs.indexManager.addIndex(indexDef, false);
future.get();
assertIndexedOne(cfs, ByteBufferUtil.bytes("birthdate"), 1L);
}
use of org.apache.cassandra.schema.IndexMetadata in project cassandra by apache.
the class RangeTombstoneTest method testRowWithRangeTombstonesUpdatesSecondaryIndex.
@Test
public void testRowWithRangeTombstonesUpdatesSecondaryIndex() throws Exception {
Keyspace table = Keyspace.open(KSNAME);
ColumnFamilyStore cfs = table.getColumnFamilyStore(CFNAME);
ByteBuffer key = ByteBufferUtil.bytes("k5");
ByteBuffer indexedColumnName = ByteBufferUtil.bytes("val");
cfs.truncateBlocking();
cfs.disableAutoCompaction();
ColumnMetadata cd = cfs.metadata().getColumn(indexedColumnName).copy();
IndexMetadata indexDef = IndexMetadata.fromIndexTargets(Collections.singletonList(new IndexTarget(cd.name, IndexTarget.Type.VALUES)), "test_index", IndexMetadata.Kind.CUSTOM, ImmutableMap.of(IndexTarget.CUSTOM_INDEX_OPTION_NAME, StubIndex.class.getName()));
TableMetadata current = cfs.metadata();
if (!current.indexes.get("test_index").isPresent()) {
TableMetadata updated = current.unbuild().indexes(current.indexes.with(indexDef)).build();
MigrationManager.announceTableUpdate(updated, true);
}
Future<?> rebuild = cfs.indexManager.addIndex(indexDef, false);
// If rebuild there is, wait for the rebuild to finish so it doesn't race with the following insertions
if (rebuild != null)
rebuild.get();
StubIndex index = (StubIndex) cfs.indexManager.listIndexes().stream().filter(i -> "test_index".equals(i.getIndexMetadata().name)).findFirst().orElseThrow(() -> new RuntimeException(new AssertionError("Index not found")));
index.reset();
UpdateBuilder builder = UpdateBuilder.create(cfs.metadata(), key).withTimestamp(0);
for (int i = 0; i < 10; i++) builder.newRow(i).add("val", i);
builder.applyUnsafe();
cfs.forceBlockingFlush();
new RowUpdateBuilder(cfs.metadata(), 0, key).addRangeTombstone(0, 7).build().applyUnsafe();
cfs.forceBlockingFlush();
assertEquals(10, index.rowsInserted.size());
CompactionManager.instance.performMaximal(cfs, false);
// compacted down to single sstable
assertEquals(1, cfs.getLiveSSTables().size());
assertEquals(8, index.rowsDeleted.size());
}
Aggregations