syncbase: improve comments about concurrency

- Updates client-facing model.go's to mention what happens
  with Scan/Exec and concurrent writes
- Updates storage engine model.go to document concurrency
  semantics
- Other misc related comment tweaks

Change-Id: Iad5f50334ae942ffab06170caf5ec8c9c4b270bf
diff --git a/v23/services/syncbase/nosql/service.vdl b/v23/services/syncbase/nosql/service.vdl
index c990976..ad6b9f5 100644
--- a/v23/services/syncbase/nosql/service.vdl
+++ b/v23/services/syncbase/nosql/service.vdl
@@ -26,9 +26,8 @@
 
 	// BeginBatch creates a new batch. It returns an App-relative name for a
 	// Database handle bound to this batch. If this Database is already bound to a
-	// batch, BeginBatch() will fail with ErrBoundToBatch.
-	//
-	// Concurrency semantics are documented in model.go.
+	// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics
+	// are documented in model.go.
 	BeginBatch(bo BatchOptions) (string | error) {access.Read}
 
 	// Commit persists the pending changes to the database.
@@ -36,9 +35,8 @@
 	// ErrNotBoundToBatch.
 	Commit() error {access.Read}
 
-	// Exec executes a syncQL query and returns all results as specified by
-	// in the query's select clause.  The returned stream reads
-	// from a consistent snapshot taken at the time of the Exec RPC.
+	// Exec executes a syncQL query and returns all results as specified by in the
+	// query's select clause. Concurrency semantics are documented in model.go.
 	Exec(query string) stream<_, []any> error {access.Read}
 
 	// Abort notifies the server that any pending changes can be discarded.
@@ -71,8 +69,8 @@
 	DeleteRowRange(start, limit []byte) error {access.Write}
 
 	// Scan returns all rows in the given half-open range [start, limit). If limit
-	// is "", all rows with keys >= start are included. The returned stream reads
-	// from a consistent snapshot taken at the time of the Scan RPC.
+	// is "", all rows with keys >= start are included. Concurrency semantics are
+	// documented in model.go.
 	Scan(start, limit []byte) stream<_, KeyValue> error {access.Read}
 
 	// GetPermissions returns an array of (prefix, perms) pairs. The array is
diff --git a/v23/services/syncbase/nosql/service.vdl.go b/v23/services/syncbase/nosql/service.vdl.go
index 2af0a60..503415e 100644
--- a/v23/services/syncbase/nosql/service.vdl.go
+++ b/v23/services/syncbase/nosql/service.vdl.go
@@ -470,17 +470,15 @@
 	Delete(*context.T, ...rpc.CallOpt) error
 	// BeginBatch creates a new batch. It returns an App-relative name for a
 	// Database handle bound to this batch. If this Database is already bound to a
-	// batch, BeginBatch() will fail with ErrBoundToBatch.
-	//
-	// Concurrency semantics are documented in model.go.
+	// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics
+	// are documented in model.go.
 	BeginBatch(ctx *context.T, bo BatchOptions, opts ...rpc.CallOpt) (string, error)
 	// Commit persists the pending changes to the database.
 	// If this Database is not bound to a batch, Commit() will fail with
 	// ErrNotBoundToBatch.
 	Commit(*context.T, ...rpc.CallOpt) error
-	// Exec executes a syncQL query and returns all results as specified by
-	// in the query's select clause.  The returned stream reads
-	// from a consistent snapshot taken at the time of the Exec RPC.
+	// Exec executes a syncQL query and returns all results as specified by in the
+	// query's select clause. Concurrency semantics are documented in model.go.
 	Exec(ctx *context.T, query string, opts ...rpc.CallOpt) (DatabaseExecClientCall, error)
 	// Abort notifies the server that any pending changes can be discarded.
 	// It is not strictly required, but it may allow the server to release locks
@@ -675,17 +673,15 @@
 	Delete(*context.T, rpc.ServerCall) error
 	// BeginBatch creates a new batch. It returns an App-relative name for a
 	// Database handle bound to this batch. If this Database is already bound to a
-	// batch, BeginBatch() will fail with ErrBoundToBatch.
-	//
-	// Concurrency semantics are documented in model.go.
+	// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics
+	// are documented in model.go.
 	BeginBatch(ctx *context.T, call rpc.ServerCall, bo BatchOptions) (string, error)
 	// Commit persists the pending changes to the database.
 	// If this Database is not bound to a batch, Commit() will fail with
 	// ErrNotBoundToBatch.
 	Commit(*context.T, rpc.ServerCall) error
-	// Exec executes a syncQL query and returns all results as specified by
-	// in the query's select clause.  The returned stream reads
-	// from a consistent snapshot taken at the time of the Exec RPC.
+	// Exec executes a syncQL query and returns all results as specified by in the
+	// query's select clause. Concurrency semantics are documented in model.go.
 	Exec(ctx *context.T, call DatabaseExecServerCall, query string) error
 	// Abort notifies the server that any pending changes can be discarded.
 	// It is not strictly required, but it may allow the server to release locks
@@ -756,17 +752,15 @@
 	Delete(*context.T, rpc.ServerCall) error
 	// BeginBatch creates a new batch. It returns an App-relative name for a
 	// Database handle bound to this batch. If this Database is already bound to a
-	// batch, BeginBatch() will fail with ErrBoundToBatch.
-	//
-	// Concurrency semantics are documented in model.go.
+	// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics
+	// are documented in model.go.
 	BeginBatch(ctx *context.T, call rpc.ServerCall, bo BatchOptions) (string, error)
 	// Commit persists the pending changes to the database.
 	// If this Database is not bound to a batch, Commit() will fail with
 	// ErrNotBoundToBatch.
 	Commit(*context.T, rpc.ServerCall) error
-	// Exec executes a syncQL query and returns all results as specified by
-	// in the query's select clause.  The returned stream reads
-	// from a consistent snapshot taken at the time of the Exec RPC.
+	// Exec executes a syncQL query and returns all results as specified by in the
+	// query's select clause. Concurrency semantics are documented in model.go.
 	Exec(ctx *context.T, call *DatabaseExecServerCallStub, query string) error
 	// Abort notifies the server that any pending changes can be discarded.
 	// It is not strictly required, but it may allow the server to release locks
@@ -869,7 +863,7 @@
 		},
 		{
 			Name: "BeginBatch",
-			Doc:  "// BeginBatch creates a new batch. It returns an App-relative name for a\n// Database handle bound to this batch. If this Database is already bound to a\n// batch, BeginBatch() will fail with ErrBoundToBatch.\n//\n// Concurrency semantics are documented in model.go.",
+			Doc:  "// BeginBatch creates a new batch. It returns an App-relative name for a\n// Database handle bound to this batch. If this Database is already bound to a\n// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics\n// are documented in model.go.",
 			InArgs: []rpc.ArgDesc{
 				{"bo", ``}, // BatchOptions
 			},
@@ -885,7 +879,7 @@
 		},
 		{
 			Name: "Exec",
-			Doc:  "// Exec executes a syncQL query and returns all results as specified by\n// in the query's select clause.  The returned stream reads\n// from a consistent snapshot taken at the time of the Exec RPC.",
+			Doc:  "// Exec executes a syncQL query and returns all results as specified by in the\n// query's select clause. Concurrency semantics are documented in model.go.",
 			InArgs: []rpc.ArgDesc{
 				{"query", ``}, // string
 			},
@@ -957,8 +951,8 @@
 	// limit is "", all rows with keys >= start are included.
 	DeleteRowRange(ctx *context.T, start []byte, limit []byte, opts ...rpc.CallOpt) error
 	// Scan returns all rows in the given half-open range [start, limit). If limit
-	// is "", all rows with keys >= start are included. The returned stream reads
-	// from a consistent snapshot taken at the time of the Scan RPC.
+	// is "", all rows with keys >= start are included. Concurrency semantics are
+	// documented in model.go.
 	Scan(ctx *context.T, start []byte, limit []byte, opts ...rpc.CallOpt) (TableScanClientCall, error)
 	// GetPermissions returns an array of (prefix, perms) pairs. The array is
 	// sorted from longest prefix to shortest, so element zero is the one that
@@ -1118,8 +1112,8 @@
 	// limit is "", all rows with keys >= start are included.
 	DeleteRowRange(ctx *context.T, call rpc.ServerCall, start []byte, limit []byte) error
 	// Scan returns all rows in the given half-open range [start, limit). If limit
-	// is "", all rows with keys >= start are included. The returned stream reads
-	// from a consistent snapshot taken at the time of the Scan RPC.
+	// is "", all rows with keys >= start are included. Concurrency semantics are
+	// documented in model.go.
 	Scan(ctx *context.T, call TableScanServerCall, start []byte, limit []byte) error
 	// GetPermissions returns an array of (prefix, perms) pairs. The array is
 	// sorted from longest prefix to shortest, so element zero is the one that
@@ -1155,8 +1149,8 @@
 	// limit is "", all rows with keys >= start are included.
 	DeleteRowRange(ctx *context.T, call rpc.ServerCall, start []byte, limit []byte) error
 	// Scan returns all rows in the given half-open range [start, limit). If limit
-	// is "", all rows with keys >= start are included. The returned stream reads
-	// from a consistent snapshot taken at the time of the Scan RPC.
+	// is "", all rows with keys >= start are included. Concurrency semantics are
+	// documented in model.go.
 	Scan(ctx *context.T, call *TableScanServerCallStub, start []byte, limit []byte) error
 	// GetPermissions returns an array of (prefix, perms) pairs. The array is
 	// sorted from longest prefix to shortest, so element zero is the one that
@@ -1276,7 +1270,7 @@
 		},
 		{
 			Name: "Scan",
-			Doc:  "// Scan returns all rows in the given half-open range [start, limit). If limit\n// is \"\", all rows with keys >= start are included. The returned stream reads\n// from a consistent snapshot taken at the time of the Scan RPC.",
+			Doc:  "// Scan returns all rows in the given half-open range [start, limit). If limit\n// is \"\", all rows with keys >= start are included. Concurrency semantics are\n// documented in model.go.",
 			InArgs: []rpc.ArgDesc{
 				{"start", ``}, // []byte
 				{"limit", ``}, // []byte
diff --git a/v23/syncbase/nosql/model.go b/v23/syncbase/nosql/model.go
index bd0903b..858c59a 100644
--- a/v23/syncbase/nosql/model.go
+++ b/v23/syncbase/nosql/model.go
@@ -34,12 +34,14 @@
 	ListTables(ctx *context.T) ([]string, error)
 
 	// Exec executes a syncQL query.
-	// If no error is returned, Exec returns an array of headers (i.e., column names)
-	// and a result stream which contains an array of values for each row that matches
-	// the query.  The number of values returned in each row of the result stream will
-	// match the size of the headers string array.
-	// TODO(jkline): Our storage engines don't yet reflect prior puts or deletes
-	// performed inside the batch.  This also applies to Scan.
+	// If no error is returned, Exec returns an array of headers (i.e., column
+	// names) and a result stream which contains an array of values for each row
+	// that matches the query.  The number of values returned in each row of the
+	// result stream will match the size of the headers string array.
+	// Concurrency semantics: It is legal to perform writes concurrently with
+	// Exec. The returned stream reads from a consistent snapshot taken at the
+	// time of the RPC, and will not reflect subsequent writes to keys not yet
+	// reached by the stream.
 	Exec(ctx *context.T, query string) ([]string, ResultStream, error)
 }
 
@@ -66,19 +68,21 @@
 	DeleteTable(ctx *context.T, relativeName string) error
 
 	// BeginBatch creates a new batch. Instead of calling this function directly,
-	// clients are recommended to use the RunInBatch() helper function, which
+	// clients are encouraged to use the RunInBatch() helper function, which
 	// detects "concurrent batch" errors and handles retries internally.
 	//
 	// Default concurrency semantics:
-	// - Reads inside a batch see a consistent snapshot, taken during
-	//   BeginBatch(), and will also see the effect of writes and deletes inside
-	//   the batch.
+	// - Reads (e.g. gets, scans) inside a batch operate over a consistent
+	//   snapshot taken during BeginBatch(), and will see the effects of prior
+	//   writes performed inside the batch.
 	// - Commit() may fail with ErrConcurrentBatch, indicating that after
 	//   BeginBatch() but before Commit(), some concurrent routine wrote to a key
-	//   that matches a key or row-range read inside this batch. (Writes inside a
-	//   batch cannot cause that batch's Commit() to fail.)
-	// - Other methods (e.g. Get) will never fail with error ErrConcurrentBatch,
-	//   even if it is known that Commit() will fail with this error.
+	//   that matches a key or row-range read inside this batch.
+	// - Other methods will never fail with error ErrConcurrentBatch, even if it
+	//   is known that Commit() will fail with this error.
+	//
+	// Once a batch has been committed or aborted, subsequent method calls will
+	// fail with no effect.
 	//
 	// Concurrency semantics can be configured using BatchOptions.
 	// TODO(sadovsky): Maybe use varargs for options.
@@ -156,8 +160,11 @@
 	Delete(ctx *context.T, r RowRange) error
 
 	// Scan returns all rows in the given half-open range [start, limit). If limit
-	// is "", all rows with keys >= start are included. The returned stream reads
-	// from a consistent snapshot taken at the time of the Scan RPC.
+	// is "", all rows with keys >= start are included.
+	// Concurrency semantics: It is legal to perform writes concurrently with
+	// Scan. The returned stream reads from a consistent snapshot taken at the
+	// time of the RPC, and will not reflect subsequent writes to keys not yet
+	// reached by the stream.
 	// See helpers nosql.Prefix(), nosql.Range(), nosql.SingleRow().
 	Scan(ctx *context.T, r RowRange) Stream
 
@@ -233,7 +240,8 @@
 	Cancel()
 }
 
-// ResultStream is an interface for iterating through rows resulting from an Exec.
+// ResultStream is an interface for iterating through rows resulting from an
+// Exec.
 type ResultStream interface {
 	// Advance stages an result so the client can retrieve it with Result.
 	// Advance returns true iff there is a result to retrieve. The client must
diff --git a/x/ref/services/syncbase/store/model.go b/x/ref/services/syncbase/store/model.go
index 5155cd9..a2c48f0 100644
--- a/x/ref/services/syncbase/store/model.go
+++ b/x/ref/services/syncbase/store/model.go
@@ -19,8 +19,11 @@
 	// fails with ErrUnknownKey.
 	Get(key, valbuf []byte) ([]byte, error)
 
-	// Scan returns all rows with keys in range [start, limit).
-	// TODO(sadovsky): Describe the behavior of Scan with concurrent writes.
+	// Scan returns all rows with keys in range [start, limit). If limit is "",
+	// all rows with keys >= start are included.
+	// Concurrency semantics: It is legal to perform writes concurrently with
+	// Scan. The returned stream may or may not reflect subsequent writes to keys
+	// not yet reached by the stream.
 	Scan(start, limit []byte) Stream
 }
 
@@ -56,9 +59,21 @@
 	NewSnapshot() Snapshot
 }
 
-// Transaction provides a mechanism for atomic reads and writes.
+// Transaction provides a mechanism for atomic reads and writes. Instead of
+// calling this function directly, clients are encouraged to use the
+// RunInTransaction() helper function, which detects "concurrent transaction"
+// errors and handles retries internally.
 //
-// Reads do reflect writes and deletes performed within this transaction.
+// Default concurrency semantics:
+// - Reads (e.g. gets, scans) inside a transaction operate over a consistent
+//   snapshot taken during NewTransaction(), and will see the effects of prior
+//   writes performed inside the transaction.
+// - Commit() may fail with ErrConcurrentTransaction, indicating that after
+//   NewTransaction() but before Commit(), some concurrent routine wrote to a
+//   key that matches a key or row-range read inside this transaction.
+// - Other methods will never fail with error ErrConcurrentTransaction, even if
+//   it is known that Commit() will fail with this error.
+//
 // Once a transaction has been committed or aborted, subsequent method calls
 // will fail with no effect.
 type Transaction interface {