This commit is contained in:
Štefan Miklošovič 2026-07-29 13:36:43 +08:00 committed by GitHub
commit b56ddee507
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 138 additions and 5 deletions

View File

@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
@ -35,9 +36,11 @@ import org.apache.cassandra.db.filter.ClusteringIndexFilter;
import org.apache.cassandra.db.filter.ColumnFilter;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.db.rows.AbstractUnfilteredRowIterator;
import org.apache.cassandra.db.rows.BTreeRow;
import org.apache.cassandra.db.rows.BufferCell;
import org.apache.cassandra.db.rows.CellPath;
import org.apache.cassandra.db.rows.EncodingStats;
import org.apache.cassandra.db.rows.Rows;
import org.apache.cassandra.db.rows.Unfiltered;
@ -200,7 +203,22 @@ public class SimpleDataSet extends AbstractVirtualTable.AbstractDataSet
{
Object value = values.get(c);
if (null != value)
builder.addCell(BufferCell.live(c, now, decompose(c.type, value)));
{
if (c.isComplex() && c.type.isUDT())
{
UserType userType = (UserType) c.type;
ByteBuffer decompose = decompose(c.type, value);
List<ByteBuffer> unpack = userType.unpack(decompose);
for (int i = 0; i < unpack.size(); i++)
{
CellPath cellPath = userType.cellPathForField(userType.fieldName(i));
builder.addCell(BufferCell.live(c, now, unpack.get(i), cellPath));
}
}
else
builder.addCell(BufferCell.live(c, now, decompose(c.type, value)));
}
}
catch (Exception e)
{

View File

@ -28,6 +28,7 @@ import com.google.common.collect.Iterables;
import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.schema.Tables;
import org.apache.cassandra.schema.Types;
public class VirtualKeyspace
{
@ -37,6 +38,11 @@ public class VirtualKeyspace
private final ImmutableCollection<VirtualTable> tables;
public VirtualKeyspace(String name, Collection<VirtualTable> tables)
{
this(name, tables, Types.none());
}
public VirtualKeyspace(String name, Collection<VirtualTable> tables, Types types)
{
this.name = name;
this.tables = ImmutableList.copyOf(tables);
@ -50,7 +56,7 @@ public class VirtualKeyspace
if (!duplicates.isEmpty())
throw new IllegalArgumentException(String.format("Duplicate table names in virtual keyspace %s: %s", name, duplicates));
this.metadata = KeyspaceMetadata.virtual(name, Tables.of(Iterables.transform(tables, VirtualTable::metadata)));
this.metadata = KeyspaceMetadata.virtual(name, Tables.of(Iterables.transform(tables, VirtualTable::metadata)), types);
}
public String name()

View File

@ -17,11 +17,17 @@
*/
package org.apache.cassandra.db.virtual;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.BytesType;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.KeyspaceMetadata;
@ -37,7 +43,10 @@ public final class VirtualSchemaKeyspace extends VirtualKeyspace
private VirtualSchemaKeyspace()
{
super(VIRTUAL_SCHEMA, ImmutableList.of(new VirtualKeyspaces(VIRTUAL_SCHEMA), new VirtualTables(VIRTUAL_SCHEMA), new VirtualColumns(VIRTUAL_SCHEMA)));
super(VIRTUAL_SCHEMA, List.of(new VirtualKeyspaces(VIRTUAL_SCHEMA),
new VirtualTables(VIRTUAL_SCHEMA),
new VirtualColumns(VIRTUAL_SCHEMA),
new VirtualTypes(VIRTUAL_SCHEMA)));
}
private static final class VirtualKeyspaces extends AbstractVirtualTable
@ -149,4 +158,43 @@ public final class VirtualSchemaKeyspace extends VirtualKeyspace
return result;
}
}
private static final class VirtualTypes extends AbstractVirtualTable
{
private static final String KEYSPACE_NAME = "keyspace_name";
private static final String TYPE_NAME = "type_name";
private static final String FIELD_NAMES = "field_names";
private static final String FIELD_TYPES = "field_types";
private VirtualTypes(String keyspace)
{
super(TableMetadata.builder(keyspace, "types")
.comment("virtual types definitions")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(KEYSPACE_NAME, UTF8Type.instance)
.addClusteringColumn(TYPE_NAME, UTF8Type.instance)
.addRegularColumn(FIELD_NAMES, ListType.getInstance(UTF8Type.instance,false).freeze())
.addRegularColumn(FIELD_TYPES, ListType.getInstance(UTF8Type.instance,false).freeze())
.build());
}
@Override
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata);
for (KeyspaceMetadata keyspace : VirtualKeyspaceRegistry.instance.virtualKeyspacesMetadata())
{
for (UserType type : keyspace.types)
{
result.row(keyspace.name, type.getNameAsString())
.column(FIELD_NAMES, type.fieldNames().stream().map(FieldIdentifier::toString).collect(Collectors.toList()))
.column(FIELD_TYPES, type.fieldTypes().stream().map(AbstractType::asCQL3Type).map(CQL3Type::toString).collect(Collectors.toList()));
}
}
return result;
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.db.virtual;
import java.util.List;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.db.marshal.LongType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.marshal.UserType;
public final class VirtualTypesDefinitions
{
public static UserType getGuardrailsThresholdSettings(String keyspace)
{
return new UserType(keyspace,
UTF8Type.instance.decompose("settings"),
List.of(FieldIdentifier.forQuoted("warn"),
FieldIdentifier.forQuoted("fail")),
List.of(LongType.instance, LongType.instance),
true);
}
private VirtualTypesDefinitions()
{
}
}

View File

@ -130,7 +130,12 @@ public final class KeyspaceMetadata implements SchemaElement
public static KeyspaceMetadata virtual(String name, Tables tables)
{
return new KeyspaceMetadata(name, Kind.VIRTUAL, KeyspaceParams.local(), tables, Views.none(), Types.none(), UserFunctions.none());
return virtual(name, tables, Types.none());
}
public static KeyspaceMetadata virtual(String name, Tables tables, Types userTypes)
{
return new KeyspaceMetadata(name, Kind.VIRTUAL, KeyspaceParams.local(), tables, Views.none(), userTypes, UserFunctions.none());
}
public KeyspaceMetadata withSwapped(KeyspaceParams params)

View File

@ -653,6 +653,19 @@ public class CassandraDaemon
// before that virtual table was instantiated.
// In general, there is no need to do same treatment for slow queries as by the time queries are processed
// the logging framework if fully setup already but for the sake of it and to be sure, just do it as well.
//
// UserType guardrailsThresholdSettings = VirtualTypesDefinitions.getGuardrailsThresholdSettings(VIRTUAL_GUARDRAILS);
//
// VirtualKeyspace guardrailsKeyspace = new VirtualKeyspace(VIRTUAL_GUARDRAILS,
// List.of(new GuardrailValuesTable(),
// new GuardrailEnableFlagsTable(),
// new GuardrailThresholdsTable(guardrailsThresholdSettings)),
// Types.of(guardrailsThresholdSettings));
// VirtualKeyspaceRegistry.instance.register(guardrailsKeyspace);
// flush log messages to system_views.system_logs virtual table as there were messages already logged
// before that virtual table was instantiated
LoggingSupportFactory.getLoggingSupport()
.getAppender(VirtualTableAppender.class, VirtualTableAppender.APPENDER_NAME)
.ifPresent(appender -> appender.flushBuffer(LogMessagesTable.class, LogMessagesTable.TABLE_NAME));