Skip to content

Commit 558eec1

Browse files
committed
Virtual keyspace metadata support was immplemented
1 parent 974fa12 commit 558eec1

File tree

4 files changed

+327
-16
lines changed

4 files changed

+327
-16
lines changed

cassandra_test.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import (
4444
"time"
4545
"unicode"
4646

47-
inf "gopkg.in/inf.v0"
47+
"gopkg.in/inf.v0"
4848
)
4949

5050
func TestEmptyHosts(t *testing.T) {
@@ -2019,6 +2019,24 @@ func TestGetKeyspaceMetadata(t *testing.T) {
20192019
}
20202020
}
20212021

2022+
func TestGetVirtualKeyspaceMetadata(t *testing.T) {
2023+
session := createSession(t)
2024+
defer session.Close()
2025+
2026+
virtualKeyspaceMatadata, err := session.VirtualKeyspaceMetadata("system_views")
2027+
if err != nil {
2028+
t.Fatal(err)
2029+
}
2030+
if len(virtualKeyspaceMatadata.Tables) == 0 {
2031+
t.Fatal("virtualKeyspaceMatadata.Tables is empty")
2032+
}
2033+
for _, table := range virtualKeyspaceMatadata.Tables {
2034+
if table.Keyspace != "system_views" {
2035+
t.Fatalf("Expected table keyspace to be 'system_views' but got '%s'", table.Keyspace)
2036+
}
2037+
}
2038+
}
2039+
20222040
// Integration test of just querying for data from the system.schema_keyspace table where the keyspace DOES NOT exist.
20232041
func TestGetKeyspaceMetadataFails(t *testing.T) {
20242042
session := createSession(t)

metadata.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ type KeyspaceMetadata struct {
5252
UserTypes map[string]*UserTypeMetadata
5353
}
5454

55+
// schema metadata for a virtual keyspace
56+
type VirtualKeyspaceMetadata struct {
57+
Name string
58+
Tables map[string]*VirtualTableMetadata
59+
}
60+
5561
// schema metadata for a table (a.k.a. column family)
5662
type TableMetadata struct {
5763
Keyspace string
@@ -68,6 +74,13 @@ type TableMetadata struct {
6874
OrderedColumns []string
6975
}
7076

77+
type VirtualTableMetadata struct {
78+
Keyspace string
79+
Name string
80+
Comment string
81+
Columns map[string]*VirtualColumnMetadata
82+
}
83+
7184
// schema metadata for a column
7285
type ColumnMetadata struct {
7386
Keyspace string
@@ -82,6 +95,15 @@ type ColumnMetadata struct {
8295
Index ColumnIndexMetadata
8396
}
8497

98+
type VirtualColumnMetadata struct {
99+
Keyspace string
100+
Table string
101+
Name string
102+
ClusteringOrder string
103+
Kind ColumnKind
104+
Type TypeInfo
105+
}
106+
85107
// FunctionMetadata holds metadata for function constructs
86108
type FunctionMetadata struct {
87109
Keyspace string
@@ -240,6 +262,13 @@ type schemaDescriber struct {
240262
cache map[string]*KeyspaceMetadata
241263
}
242264

265+
// queries the cluster for schema information for a virtual keyspace
266+
type virtualSchemaDescriber struct {
267+
session *Session
268+
mu sync.Mutex
269+
cache map[string]*VirtualKeyspaceMetadata
270+
}
271+
243272
// creates a session bound schema describer which will query and cache
244273
// keyspace metadata
245274
func newSchemaDescriber(session *Session) *schemaDescriber {
@@ -249,6 +278,15 @@ func newSchemaDescriber(session *Session) *schemaDescriber {
249278
}
250279
}
251280

281+
// creates a session bound schema describer which will query and cache
282+
// virtual keyspace metadata
283+
func newVirtualSchemaDescriber(session *Session) *virtualSchemaDescriber {
284+
return &virtualSchemaDescriber{
285+
session: session,
286+
cache: map[string]*VirtualKeyspaceMetadata{},
287+
}
288+
}
289+
252290
// returns the cached KeyspaceMetadata held by the describer for the named
253291
// keyspace.
254292
func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) {
@@ -269,6 +307,23 @@ func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, err
269307
return metadata, nil
270308
}
271309

310+
// returns the cached VirtualKeyspaceMetadata held by the describer for the named
311+
// keyspace.
312+
func (s *virtualSchemaDescriber) getSchema(keyspaceName string) (*VirtualKeyspaceMetadata, error) {
313+
s.mu.Lock()
314+
defer s.mu.Unlock()
315+
metadata, found := s.cache[keyspaceName]
316+
if !found {
317+
err := s.refreshSchema(keyspaceName)
318+
if err != nil {
319+
return nil, err
320+
}
321+
metadata = s.cache[keyspaceName]
322+
}
323+
324+
return metadata, nil
325+
}
326+
272327
// clears the already cached keyspace metadata
273328
func (s *schemaDescriber) clearSchema(keyspaceName string) {
274329
s.mu.Lock()
@@ -323,6 +378,42 @@ func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
323378
return nil
324379
}
325380

381+
// forcibly updates the current VirtualKeyspaceMetadata held by the virtual schema describer
382+
// for a given named keyspace.
383+
func (s *virtualSchemaDescriber) refreshSchema(keyspaceName string) error {
384+
var wg sync.WaitGroup
385+
var tables []VirtualTableMetadata
386+
var columns []VirtualColumnMetadata
387+
var err error
388+
389+
wg.Add(2)
390+
go func() {
391+
defer wg.Done()
392+
tables, err = getVirtualTableMetadata(s.session, keyspaceName)
393+
if err != nil {
394+
return
395+
}
396+
}()
397+
go func() {
398+
defer wg.Done()
399+
columns, err = getVirtualColumnMetadata(s.session, keyspaceName)
400+
if err != nil {
401+
return
402+
}
403+
}()
404+
wg.Wait()
405+
if err != nil {
406+
return err
407+
}
408+
409+
keyspaceMetadata := &VirtualKeyspaceMetadata{Name: keyspaceName}
410+
compileVirtualMetadata(keyspaceMetadata, tables, columns)
411+
412+
s.cache[keyspaceName] = keyspaceMetadata
413+
414+
return nil
415+
}
416+
326417
// "compiles" derived information about keyspace, table, and column metadata
327418
// for a keyspace from the basic queried metadata objects returned by
328419
// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
@@ -417,6 +508,33 @@ func compileMetadata(
417508
}
418509
}
419510

511+
// "compiles" derived information about virtual keyspace, table, and column metadata
512+
// for a keyspace from the basic queried metadata objects returned by
513+
// getVirtualTableMetadata, and getVirtualColumnMetadata respectively;
514+
// Links the metadata objects together.
515+
func compileVirtualMetadata(
516+
keyspace *VirtualKeyspaceMetadata,
517+
tables []VirtualTableMetadata,
518+
columns []VirtualColumnMetadata,
519+
) {
520+
keyspace.Tables = make(map[string]*VirtualTableMetadata)
521+
for i := range tables {
522+
tables[i].Columns = make(map[string]*VirtualColumnMetadata)
523+
524+
keyspace.Tables[tables[i].Name] = &tables[i]
525+
}
526+
527+
for i := range columns {
528+
col := &columns[i]
529+
table, ok := keyspace.Tables[col.Table]
530+
if !ok {
531+
continue
532+
}
533+
534+
table.Columns[col.Name] = col
535+
}
536+
}
537+
420538
// Compiles derived information from TableMetadata which have had
421539
// ColumnMetadata added already. V1 protocol does not return as much
422540
// column metadata as V2+ (because V1 doesn't support the "type" column in the
@@ -760,6 +878,28 @@ func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, e
760878
return tables, nil
761879
}
762880

881+
// query for only the table metadata in the specified keyspace from system_virtual_schema.tables
882+
func getVirtualTableMetadata(s *Session, keyspaceName string) ([]VirtualTableMetadata, error) {
883+
const stmt = `
884+
SELECT
885+
table_name,
886+
comment
887+
FROM system_virtual_schema.tables
888+
WHERE keyspace_name = ?`
889+
890+
tables := []VirtualTableMetadata{}
891+
table := VirtualTableMetadata{Keyspace: keyspaceName}
892+
893+
iter := s.control.query(stmt, keyspaceName)
894+
895+
for iter.Scan(&table.Name, &table.Comment) {
896+
tables = append(tables, table)
897+
table = VirtualTableMetadata{Keyspace: keyspaceName}
898+
}
899+
900+
return tables, nil
901+
}
902+
763903
func (s *Session) scanColumnMetadataV1(keyspace string) ([]ColumnMetadata, error) {
764904
// V1 does not support the type column, and all returned rows are
765905
// of kind "regular".
@@ -947,6 +1087,47 @@ func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata,
9471087
return columns, nil
9481088
}
9491089

1090+
// query for only the column metadata in the specified keyspace from system_virtual_schema.columns
1091+
func getVirtualColumnMetadata(s *Session, keyspaceName string) ([]VirtualColumnMetadata, error) {
1092+
const stmt = `
1093+
SELECT
1094+
table_name,
1095+
column_name,
1096+
clustering_order,
1097+
kind,
1098+
type
1099+
FROM system_virtual_schema.columns
1100+
WHERE keyspace_name = ?`
1101+
1102+
var columns []VirtualColumnMetadata
1103+
1104+
rows := s.control.query(stmt, keyspaceName).Scanner()
1105+
for rows.Next() {
1106+
var (
1107+
column = VirtualColumnMetadata{Keyspace: keyspaceName}
1108+
columnType string
1109+
)
1110+
1111+
err := rows.Scan(
1112+
&column.Table,
1113+
&column.Name,
1114+
&column.ClusteringOrder,
1115+
&column.Kind,
1116+
&columnType,
1117+
)
1118+
1119+
if err != nil {
1120+
return nil, err
1121+
}
1122+
1123+
column.Type = getCassandraType(columnType, s.logger)
1124+
1125+
columns = append(columns, column)
1126+
}
1127+
1128+
return columns, nil
1129+
}
1130+
9501131
func getTypeInfo(t string, logger StdLogger) TypeInfo {
9511132
if strings.HasPrefix(t, apacheCassandraTypePrefix) {
9521133
t = apacheToCassandraType(t)

0 commit comments

Comments
 (0)