Skip to content

Commit cd6cadd

Browse files
committed
Virtual keyspace metadata support was immplemented
1 parent 63b6d78 commit cd6cadd

File tree

4 files changed

+342
-15
lines changed

4 files changed

+342
-15
lines changed

cassandra_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,24 @@ func TestGetKeyspaceMetadata(t *testing.T) {
22082208
}
22092209
}
22102210

2211+
func TestGetVirtualKeyspaceMetadata(t *testing.T) {
2212+
session := createSession(t)
2213+
defer session.Close()
2214+
2215+
virtualKeyspaceMatadata, err := session.VirtualKeyspaceMetadata("system_views")
2216+
if err != nil {
2217+
t.Fatal(err)
2218+
}
2219+
if len(virtualKeyspaceMatadata.Tables) == 0 {
2220+
t.Fatal("virtualKeyspaceMatadata.Tables is empty")
2221+
}
2222+
for _, table := range virtualKeyspaceMatadata.Tables {
2223+
if table.Keyspace != "system_views" {
2224+
t.Fatalf("Expected table keyspace to be 'system_views' but got '%s'", table.Keyspace)
2225+
}
2226+
}
2227+
}
2228+
22112229
// Integration test of just querying for data from the system.schema_keyspace table where the keyspace DOES NOT exist.
22122230
func TestGetKeyspaceMetadataFails(t *testing.T) {
22132231
session := createSession(t)

metadata.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ type KeyspaceMetadata struct {
5050
UserTypes map[string]*UserTypeMetadata
5151
}
5252

53+
// schema metadata for a virtual keyspace
54+
type VirtualKeyspaceMetadata struct {
55+
Name string
56+
Tables map[string]*VirtualTableMetadata
57+
}
58+
5359
// schema metadata for a table (a.k.a. column family)
5460
type TableMetadata struct {
5561
Keyspace string
@@ -66,6 +72,13 @@ type TableMetadata struct {
6672
OrderedColumns []string
6773
}
6874

75+
type VirtualTableMetadata struct {
76+
Keyspace string
77+
Name string
78+
Comment string
79+
Columns map[string]*VirtualColumnMetadata
80+
}
81+
6982
// schema metadata for a column
7083
type ColumnMetadata struct {
7184
Keyspace string
@@ -80,6 +93,15 @@ type ColumnMetadata struct {
8093
Index ColumnIndexMetadata
8194
}
8295

96+
type VirtualColumnMetadata struct {
97+
Keyspace string
98+
Table string
99+
Name string
100+
ClusteringOrder string
101+
Kind ColumnKind
102+
Type TypeInfo
103+
}
104+
83105
// FunctionMetadata holds metadata for function constructs
84106
type FunctionMetadata struct {
85107
Keyspace string
@@ -231,6 +253,13 @@ type schemaDescriber struct {
231253
cache map[string]*KeyspaceMetadata
232254
}
233255

256+
// queries the cluster for schema information for a virtual keyspace
257+
type virtualSchemaDescriber struct {
258+
session *Session
259+
mu sync.Mutex
260+
cache map[string]*VirtualKeyspaceMetadata
261+
}
262+
234263
// creates a session bound schema describer which will query and cache
235264
// keyspace metadata
236265
func newSchemaDescriber(session *Session) *schemaDescriber {
@@ -240,6 +269,15 @@ func newSchemaDescriber(session *Session) *schemaDescriber {
240269
}
241270
}
242271

272+
// creates a session bound schema describer which will query and cache
273+
// virtual keyspace metadata
274+
func newVirtualSchemaDescriber(session *Session) *virtualSchemaDescriber {
275+
return &virtualSchemaDescriber{
276+
session: session,
277+
cache: map[string]*VirtualKeyspaceMetadata{},
278+
}
279+
}
280+
243281
// returns the cached KeyspaceMetadata held by the describer for the named
244282
// keyspace.
245283
func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) {
@@ -260,6 +298,23 @@ func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, err
260298
return metadata, nil
261299
}
262300

301+
// returns the cached VirtualKeyspaceMetadata held by the describer for the named
302+
// keyspace.
303+
func (s *virtualSchemaDescriber) getSchema(keyspaceName string) (*VirtualKeyspaceMetadata, error) {
304+
s.mu.Lock()
305+
defer s.mu.Unlock()
306+
metadata, found := s.cache[keyspaceName]
307+
if !found {
308+
err := s.refreshSchema(keyspaceName)
309+
if err != nil {
310+
return nil, err
311+
}
312+
metadata = s.cache[keyspaceName]
313+
}
314+
315+
return metadata, nil
316+
}
317+
263318
// clears the already cached keyspace metadata
264319
func (s *schemaDescriber) clearSchema(keyspaceName string) {
265320
s.mu.Lock()
@@ -314,6 +369,43 @@ func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
314369
return nil
315370
}
316371

372+
// forcibly updates the current VirtualKeyspaceMetadata held by the virtual schema describer
373+
// for a given named keyspace.
374+
func (s *virtualSchemaDescriber) refreshSchema(keyspaceName string) error {
375+
var wg sync.WaitGroup
376+
377+
var (
378+
tables []VirtualTableMetadata
379+
columns []VirtualColumnMetadata
380+
tableErr, columnErr error
381+
)
382+
383+
wg.Add(2)
384+
go func() {
385+
defer wg.Done()
386+
tables, tableErr = getVirtualTableMetadata(s.session, keyspaceName)
387+
}()
388+
go func() {
389+
defer wg.Done()
390+
columns, columnErr = getVirtualColumnMetadata(s.session, keyspaceName)
391+
}()
392+
wg.Wait()
393+
394+
if columnErr != nil {
395+
return columnErr
396+
}
397+
if tableErr != nil {
398+
return tableErr
399+
}
400+
401+
keyspaceMetadata := &VirtualKeyspaceMetadata{Name: keyspaceName}
402+
compileVirtualMetadata(keyspaceMetadata, tables, columns)
403+
404+
s.cache[keyspaceName] = keyspaceMetadata
405+
406+
return nil
407+
}
408+
317409
// "compiles" derived information about keyspace, table, and column metadata
318410
// for a keyspace from the basic queried metadata objects returned by
319411
// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
@@ -395,6 +487,33 @@ func compileMetadata(
395487
}
396488
}
397489

490+
// "compiles" derived information about virtual keyspace, table, and column metadata
491+
// for a keyspace from the basic queried metadata objects returned by
492+
// getVirtualTableMetadata, and getVirtualColumnMetadata respectively;
493+
// Links the metadata objects together.
494+
func compileVirtualMetadata(
495+
keyspace *VirtualKeyspaceMetadata,
496+
tables []VirtualTableMetadata,
497+
columns []VirtualColumnMetadata,
498+
) {
499+
keyspace.Tables = make(map[string]*VirtualTableMetadata)
500+
for i := range tables {
501+
tables[i].Columns = make(map[string]*VirtualColumnMetadata)
502+
503+
keyspace.Tables[tables[i].Name] = &tables[i]
504+
}
505+
506+
for i := range columns {
507+
col := &columns[i]
508+
table, ok := keyspace.Tables[col.Table]
509+
if !ok {
510+
continue
511+
}
512+
513+
table.Columns[col.Name] = col
514+
}
515+
}
516+
398517
// Compiles derived information from TableMetadata which have had
399518
// ColumnMetadata added already. V1 protocol does not return as much
400519
// column metadata as V2+ (because V1 doesn't support the "type" column in the
@@ -738,6 +857,37 @@ func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, e
738857
return tables, nil
739858
}
740859

860+
// query for only the table metadata in the specified keyspace from system_virtual_schema.tables
861+
func getVirtualTableMetadata(s *Session, keyspaceName string) ([]VirtualTableMetadata, error) {
862+
const stmt = `
863+
SELECT
864+
table_name,
865+
comment
866+
FROM system_virtual_schema.tables
867+
WHERE keyspace_name = ?`
868+
869+
tables := []VirtualTableMetadata{}
870+
table := VirtualTableMetadata{Keyspace: keyspaceName}
871+
872+
iter := s.control.query(stmt, keyspaceName)
873+
defer iter.Close()
874+
875+
if iter.err != nil {
876+
return nil, fmt.Errorf("failed to iterate virtual table metadata for keyspace: %w", iter.err)
877+
}
878+
879+
if iter.NumRows() == 0 {
880+
return nil, ErrKeyspaceDoesNotExist
881+
}
882+
883+
for iter.Scan(&table.Name, &table.Comment) {
884+
tables = append(tables, table)
885+
table = VirtualTableMetadata{Keyspace: keyspaceName}
886+
}
887+
888+
return tables, nil
889+
}
890+
741891
func (s *Session) scanColumnMetadataV1(keyspace string) ([]ColumnMetadata, error) {
742892
// V1 does not support the type column, and all returned rows are
743893
// of kind "regular".
@@ -925,6 +1075,52 @@ func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata,
9251075
return columns, nil
9261076
}
9271077

1078+
// query for only the column metadata in the specified keyspace from system_virtual_schema.columns
1079+
func getVirtualColumnMetadata(s *Session, keyspaceName string) ([]VirtualColumnMetadata, error) {
1080+
const stmt = `
1081+
SELECT
1082+
table_name,
1083+
column_name,
1084+
clustering_order,
1085+
kind,
1086+
type
1087+
FROM system_virtual_schema.columns
1088+
WHERE keyspace_name = ?`
1089+
1090+
var columns []VirtualColumnMetadata
1091+
1092+
rows := s.control.query(stmt, keyspaceName).Scanner()
1093+
1094+
for rows.Next() {
1095+
var (
1096+
column = VirtualColumnMetadata{Keyspace: keyspaceName}
1097+
columnType string
1098+
)
1099+
1100+
err := rows.Scan(
1101+
&column.Table,
1102+
&column.Name,
1103+
&column.ClusteringOrder,
1104+
&column.Kind,
1105+
&columnType,
1106+
)
1107+
1108+
if err != nil {
1109+
return nil, err
1110+
}
1111+
1112+
column.Type = getCassandraType(columnType, s.logger)
1113+
1114+
columns = append(columns, column)
1115+
}
1116+
1117+
if err := rows.Err(); err != nil {
1118+
return nil, fmt.Errorf("failed to iterate virtual column metadata for keyspace: %w", err)
1119+
}
1120+
1121+
return columns, nil
1122+
}
1123+
9281124
func getTypeInfo(t string, logger StdLogger) TypeInfo {
9291125
if strings.HasPrefix(t, apacheCassandraTypePrefix) {
9301126
t = apacheToCassandraType(t)

0 commit comments

Comments
 (0)