Add schema to syncbase
1) Add client APIs related to managing db schema
- adds schema arg to NoSQLDatabase() bind
- adds db.UpgradeIfOutdated() method
- adds db.GetSchemaManager() which returns an object with {Get,Set}SchemaMetadata
- adds Schema{metadata, upgrader} struct and SchemaUpgrader interface
2) Add vdl changes
- {Get,Set}SchemaMetadata methods
- optional SchemaMetadata arg to Database.Create
MultiPart: 1/2
Change-Id: Ia920bbc55c40145cbacf8245c4d1682dcb02496d
diff --git a/services/syncbase/server/app.go b/services/syncbase/server/app.go
index 0c8958f..8862f57 100644
--- a/services/syncbase/server/app.go
+++ b/services/syncbase/server/app.go
@@ -9,6 +9,7 @@
"sync"
wire "v.io/syncbase/v23/services/syncbase"
+ nosqlwire "v.io/syncbase/v23/services/syncbase/nosql"
"v.io/syncbase/x/ref/services/syncbase/server/interfaces"
"v.io/syncbase/x/ref/services/syncbase/server/nosql"
"v.io/syncbase/x/ref/services/syncbase/server/util"
@@ -132,7 +133,7 @@
return dbNames, nil
}
-func (a *app) CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions) error {
+func (a *app) CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions, metadata *nosqlwire.SchemaMetadata) error {
if !a.exists {
vlog.Fatalf("app %q does not exist", a.name)
}
@@ -182,7 +183,7 @@
if perms == nil {
perms = aData.Perms
}
- d, err := nosql.NewDatabase(ctx, a, dbName, nosql.DatabaseOptions{
+ d, err := nosql.NewDatabase(ctx, a, dbName, metadata, nosql.DatabaseOptions{
Perms: perms,
RootDir: rootDir,
Engine: engine,
diff --git a/services/syncbase/server/interfaces/app.go b/services/syncbase/server/interfaces/app.go
index b1d5d4f..e990b29 100644
--- a/services/syncbase/server/interfaces/app.go
+++ b/services/syncbase/server/interfaces/app.go
@@ -5,6 +5,7 @@
package interfaces
import (
+ wire "v.io/syncbase/v23/services/syncbase/nosql"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security/access"
@@ -22,7 +23,7 @@
NoSQLDatabaseNames(ctx *context.T, call rpc.ServerCall) ([]string, error)
// CreateNoSQLDatabase creates the specified NoSQL database.
- CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions) error
+ CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions, metadata *wire.SchemaMetadata) error
// DeleteNoSQLDatabase deletes the specified NoSQL database.
DeleteNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string) error
diff --git a/services/syncbase/server/nosql/database.go b/services/syncbase/server/nosql/database.go
index 2da519e..bfe419a 100644
--- a/services/syncbase/server/nosql/database.go
+++ b/services/syncbase/server/nosql/database.go
@@ -99,7 +99,7 @@
// NewDatabase creates a new database instance and returns it.
// Designed for use from within App.CreateNoSQLDatabase.
-func NewDatabase(ctx *context.T, a interfaces.App, name string, opts DatabaseOptions) (*database, error) {
+func NewDatabase(ctx *context.T, a interfaces.App, name string, metadata *wire.SchemaMetadata, opts DatabaseOptions) (*database, error) {
if opts.Perms == nil {
return nil, verror.New(verror.ErrInternal, ctx, "perms must be specified")
}
@@ -108,8 +108,9 @@
return nil, err
}
data := &databaseData{
- Name: d.name,
- Perms: opts.Perms,
+ Name: d.name,
+ Perms: opts.Perms,
+ SchemaMetadata: metadata,
}
if err := util.Put(ctx, d.st, d.stKey(), data); err != nil {
return nil, err
@@ -120,7 +121,7 @@
////////////////////////////////////////
// RPC methods
-func (d *databaseReq) Create(ctx *context.T, call rpc.ServerCall, perms access.Permissions) error {
+func (d *databaseReq) Create(ctx *context.T, call rpc.ServerCall, perms access.Permissions, metadata *wire.SchemaMetadata) error {
if d.exists {
return verror.New(verror.ErrExist, ctx, d.name)
}
@@ -130,7 +131,7 @@
// This database does not yet exist; d is just an ephemeral handle that holds
// {name string, a *app}. d.a.CreateNoSQLDatabase will create a new database
// handle and store it in d.a.dbs[d.name].
- return d.a.CreateNoSQLDatabase(ctx, call, d.name, perms)
+ return d.a.CreateNoSQLDatabase(ctx, call, d.name, perms, metadata)
}
func (d *databaseReq) Delete(ctx *context.T, call rpc.ServerCall) error {
diff --git a/services/syncbase/server/nosql/database_sm.go b/services/syncbase/server/nosql/database_sm.go
new file mode 100644
index 0000000..5f69585
--- /dev/null
+++ b/services/syncbase/server/nosql/database_sm.go
@@ -0,0 +1,53 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package nosql
+
+import (
+ wire "v.io/syncbase/v23/services/syncbase/nosql"
+ "v.io/syncbase/x/ref/services/syncbase/server/util"
+ "v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/context"
+ "v.io/v23/rpc"
+ "v.io/v23/verror"
+)
+
+////////////////////////////////////////
+// SchemaManager RPC methods
+
+func (d *databaseReq) GetSchemaMetadata(ctx *context.T, call rpc.ServerCall) (wire.SchemaMetadata, error) {
+ metadata := wire.SchemaMetadata{}
+
+ if !d.exists {
+ return metadata, verror.New(verror.ErrNoExist, ctx, d.Name())
+ }
+
+ // Check permissions on Database and retreve schema metadata.
+ dbData := databaseData{}
+ if err := util.GetWithAuth(ctx, call, d.st, d.stKey(), &dbData); err != nil {
+ return metadata, err
+ }
+ if dbData.SchemaMetadata == nil {
+ return metadata, verror.New(verror.ErrNoExist, ctx, "Schema does not exist for the db")
+ }
+ return *dbData.SchemaMetadata, nil
+}
+
+func (d *databaseReq) SetSchemaMetadata(ctx *context.T, call rpc.ServerCall, metadata wire.SchemaMetadata) error {
+ // Check if database exists
+ if !d.exists {
+ return verror.New(verror.ErrNoExist, ctx, "database: "+d.Name())
+ }
+
+ // Check permissions on Database and store schema metadata.
+ return store.RunInTransaction(d.st, func(st store.StoreReadWriter) error {
+ dbData := databaseData{}
+ return util.UpdateWithAuth(ctx, call, st, d.stKey(), &dbData, func() error {
+ // NOTE: For now we expect the client to not issue multiple
+ // concurrent SetSchemaMetadata calls.
+ dbData.SchemaMetadata = &metadata
+ return nil
+ })
+ })
+}
diff --git a/services/syncbase/server/nosql/types.vdl b/services/syncbase/server/nosql/types.vdl
index 33d3883..8ede239 100644
--- a/services/syncbase/server/nosql/types.vdl
+++ b/services/syncbase/server/nosql/types.vdl
@@ -6,13 +6,15 @@
import (
"v.io/v23/security/access"
+ "v.io/syncbase/v23/services/syncbase/nosql"
)
// databaseData represents the persistent state of a Database.
type databaseData struct {
- Name string
- Version uint64 // covers the fields below
- Perms access.Permissions
+ Name string
+ Version uint64 // covers the Perms field below
+ Perms access.Permissions
+ SchemaMetadata ?nosql.SchemaMetadata
}
// tableData represents the persistent state of a Table.
diff --git a/services/syncbase/server/nosql/types.vdl.go b/services/syncbase/server/nosql/types.vdl.go
index 021cef6..bf5f346 100644
--- a/services/syncbase/server/nosql/types.vdl.go
+++ b/services/syncbase/server/nosql/types.vdl.go
@@ -12,14 +12,16 @@
"v.io/v23/vdl"
// VDL user imports
+ "v.io/syncbase/v23/services/syncbase/nosql"
"v.io/v23/security/access"
)
// databaseData represents the persistent state of a Database.
type databaseData struct {
- Name string
- Version uint64 // covers the fields below
- Perms access.Permissions
+ Name string
+ Version uint64 // covers the Perms field below
+ Perms access.Permissions
+ SchemaMetadata *nosql.SchemaMetadata
}
func (databaseData) __VDLReflect(struct {
diff --git a/services/syncbase/vsync/test_util.go b/services/syncbase/vsync/test_util.go
index 556b2d7..9dd4e3e 100644
--- a/services/syncbase/vsync/test_util.go
+++ b/services/syncbase/vsync/test_util.go
@@ -12,6 +12,7 @@
"testing"
"time"
+ wire "v.io/syncbase/v23/services/syncbase/nosql"
"v.io/syncbase/x/ref/services/syncbase/server/interfaces"
"v.io/syncbase/x/ref/services/syncbase/server/util"
"v.io/syncbase/x/ref/services/syncbase/server/watchable"
@@ -62,7 +63,7 @@
return []string{"mockdb"}, nil
}
-func (a *mockApp) CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions) error {
+func (a *mockApp) CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions, metadata *wire.SchemaMetadata) error {
return verror.NewErrNotImplemented(ctx)
}
diff --git a/syncbase/sb51/shell.go b/syncbase/sb51/shell.go
index a41d245..b5f18c0 100644
--- a/syncbase/sb51/shell.go
+++ b/syncbase/sb51/shell.go
@@ -154,7 +154,7 @@
return nil, err
}
}
- d := app.NoSQLDatabase(dbName)
+ d := app.NoSQLDatabase(dbName, nil)
if exists, err := d.Exists(ctx); err != nil {
return nil, fmt.Errorf("failed checking for db %q: %v", d.FullName(), err)
} else if !exists {