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 {