client

package
v0.0.0-...-d6fed6f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2015 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package client provides clients for accessing the various externally-facing Cockroach database endpoints.

DB Client

The DB client is a fully-featured client of Cockroach's key-value database. It provides a simple, synchronous interface well-suited to parallel updates and queries.

The simplest way to use the client is through the Run method. Run synchronously invokes the call, fills in the the reply and returns an error. The example below shows a get and a put.

db, err := client.Open("https://root@localhost:8080")
if err != nil {
	log.Fatal(err)
}
if err := db.Put("a", "hello"); err != nil {
	log.Fatal(err)
}
if gr, err := db.Get("a"); err != nil {
	log.Fatal(err)
} else {
	log.Printf("%s", gr.ValueBytes())  // "hello"
}

The API is synchronous, but accommodates efficient parallel updates and queries using Batch objects. An arbitrary number of calls may be added to a Batch which is executed using DB.Run. Note however that the individual calls within a batch are not guaranteed to have atomic semantics. A transaction must be used to guarantee atomicity. A simple example of using a Batch which does two scans in parallel and then sends a sequence of puts in parallel:

db, err := client.Open("https://root@localhost:8080")
if err != nil {
	log.Fatal(err)
}

b1 := &client.Batch{}
b1.Scan("a", "c\x00", 1000)
b1.Scan("x", "z\x00", 1000)

// Run sends both scans in parallel and returns the first error or nil.
if err := db.Run(b1); err != nil {
	log.Fatal(err)
}

acResult := b1.Results[0]
xzResult := b1.Results[1]

// Append maximum value from "a"-"c" to all values from "x"-"z".
max := []byte(nil)
for _, row := range acResult.Rows {
	if bytes.Compare(max, row.ValueBytes()) < 0 {
		max = row.ValueBytes()
	}
}

b2 := &client.Batch{}
for _, row := range xzResult.Rows {
	b2.Put(row.Key, bytes.Join([][]byte{row.ValueBytes(), max}, []byte(nil)))
}

// Run all puts for parallel execution.
if err := db.Run(b2); err != nil {
	log.Fatal(err)
}

Transactions are supported through the DB.Txn() method, which takes a retryable function, itself composed of the same simple mix of API calls typical of a non-transactional operation. Within the context of the Txn() call, all method invocations are transparently given necessary transactional details, and conflicts are handled with backoff/retry loops and transaction restarts as necessary. An example of using transactions with parallel writes:

db, err := client.Open("https://root@localhost:8080")
if err != nil {
	log.Fatal(err)
}

err := db.Txn(func(txn *client.Txn) error {
	b := &client.Batch{}
	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("testkey-%02d", i)
		b.Put(key, "test value")
	}

	// Note that the Txn client is flushed automatically when this function
	// returns success (i.e. nil). Calling CommitInBatch explicitly can
	// sometimes reduce the number of RPCs.
	return txn.CommitInBatch(b)
})
if err != nil {
	log.Fatal(err)
}

Note that with Cockroach's lock-free transactions, clients should expect retries as a matter of course. This is why the transaction functionality is exposed through a retryable function. The retryable function should have no side effects which are not idempotent.

Transactions should endeavor to use batches to perform multiple operations in a single RPC. In addition to the reduced number of RPCs to the server, this allows writes to the same range to be batched together. In cases where the entire transaction affects only a single range, transactions can commit in a single round trip.

Example (Accounting)

Example_accounting shows how to use the admin client to get/set/list/delete accounting configs.

package main

import (
	"fmt"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util/log"
)

func main() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Accounting)

	const yamlConfig = `cluster_id: test`
	const jsonConfig = `{
  "cluster_id": "test"
}`
	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON accounting config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML accounting config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Accounting prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Accounting prefixes: %q\n", keys)

}
Output:

Set YAML accounting config for ""
Set YAML accounting config for "db1"
Set JSON accounting config for "db 2"
Set JSON accounting config for "\xfe"
JSON config for "db1":
{
  "cluster_id": "test"
}
YAML config for "db 2":
cluster_id: test

Accounting prefixes: ["" "db 2" "db1" "\xfe"]
Accounting prefixes: ["" "db1" "\xfe"]
Example (Permission)

Example_permission shows how to use the admin client to get/set/list/delete permission configs.

package main

import (
	"fmt"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util/log"
)

func main() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Permission)

	// The test server creates a permission config entry for 'server.TestUser'.
	// Delete it first so it does not interfere with our configs.
	err := client.Delete(server.TestUser)
	if err != nil {
		log.Fatal(err)
	}

	const yamlConfig = `
read: [readonly, readwrite]
write: [readwrite, writeonly]
`
	const jsonConfig = `{
	   "read": [
	     "readonly",
	     "readwrite"
	   ],
	   "write": [
	     "readwrite",
	     "writeonly"
	   ]
	 }`

	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON permission config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML permission config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Permission prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Permission prefixes: %q\n", keys)

}
Output:

Set YAML permission config for ""
Set YAML permission config for "db1"
Set JSON permission config for "db 2"
Set JSON permission config for "\xfe"
JSON config for "db1":
{
  "read": [
    "readonly",
    "readwrite"
  ],
  "write": [
    "readwrite",
    "writeonly"
  ]
}
YAML config for "db 2":
read:
- readonly
- readwrite
write:
- readwrite
- writeonly

Permission prefixes: ["" "db 2" "db1" "\xfe"]
Permission prefixes: ["" "db1" "\xfe"]
Example (User)

Example_user shows how to use the admin client to get/set/list/delete user configs.

package main

import (
	"fmt"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util/log"
)

func main() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.User)

	const yamlConfig = `hashed_password:
 - 10
 - 20`
	const jsonConfig = `{
	   "hashed_password": "ChQ="
	 }`
	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Overwriting the default entry fails.
	err := client.SetYAML("", yamlConfig)
	if err == nil {
		log.Fatal("expected error")
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON user config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML user config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Users: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Users: %q\n", keys)

}
Output:

Set YAML user config for "db1"
Set JSON user config for "db 2"
Set JSON user config for "\xfe"
JSON config for "db1":
{
  "hashed_password": "ChQ="
}
YAML config for "db 2":
hashed_password:
- 10
- 20

Users: ["" "db 2" "db1" "\xfe"]
Users: ["" "db1" "\xfe"]
Example (Zone)

Example_zone shows how to use the admin client to get/set/list/delete zone configs.

package main

import (
	"fmt"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util/log"
)

func main() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Zone)

	const yamlConfig = `
replicas:
  - attrs: [dc1, ssd]
  - attrs: [dc2, ssd]
  - attrs: [dc3, ssd]
range_min_bytes: 1048576
range_max_bytes: 67108864
`
	const jsonConfig = `{
	   "replica_attrs": [
	     {
	       "attrs": [
	         "dc1",
	         "ssd"
	       ]
	     },
	     {
	       "attrs": [
	         "dc2",
	         "ssd"
	       ]
	     },
	     {
	       "attrs": [
	         "dc3",
	         "ssd"
	       ]
	     }
	   ],
	   "range_min_bytes": 1048576,
	   "range_max_bytes": 67108864
	 }`

	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON zone config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML zone config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Zone prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Zone prefixes: %q\n", keys)

}
Output:

Set YAML zone config for ""
Set YAML zone config for "db1"
Set JSON zone config for "db 2"
Set JSON zone config for "\xfe"
JSON config for "db1":
{
  "replica_attrs": [
    {
      "attrs": [
        "dc1",
        "ssd"
      ]
    },
    {
      "attrs": [
        "dc2",
        "ssd"
      ]
    },
    {
      "attrs": [
        "dc3",
        "ssd"
      ]
    }
  ],
  "range_min_bytes": 1048576,
  "range_max_bytes": 67108864
}
YAML config for "db 2":
replicas:
- attrs: [dc1, ssd]
- attrs: [dc2, ssd]
- attrs: [dc3, ssd]
range_min_bytes: 1048576
range_max_bytes: 67108864

Zone prefixes: ["" "db 2" "db1" "\xfe"]
Zone prefixes: ["" "db1" "\xfe"]

Index

Examples

Constants

View Source
const (

	// Accounting expects config.AcctConfig
	Accounting = "acct"
	// Permission expects config.PermConfig
	Permission = "perms"
	// Quit only handles Get requests.
	Quit = "quit"
	// User expects config.UserConfig
	User = "users"
	// Zone expects config.ZoneConfig.
	Zone = "zones"
)
View Source
const (
	// KVDBEndpoint is the URL path prefix which accepts incoming
	// HTTP requests for the KV API.
	KVDBEndpoint = "/kv/db/"
	// StatusTooManyRequests indicates client should retry due to
	// server having too many requests.
	StatusTooManyRequests = 429
)

Variables

View Source
var (
	// DefaultTxnRetryOptions are the standard retry options used
	// for transactions.
	// This is exported for testing purposes only.
	DefaultTxnRetryOptions = retry.Options{
		InitialBackoff: 50 * time.Millisecond,
		MaxBackoff:     5 * time.Second,
		Multiplier:     2,
	}
)

Functions

func HTTPPost

func HTTPPost(c PostContext, request, response gogoproto.Message, method fmt.Stringer) error

HTTPPost posts the req using the HTTP client. The call's method is appended to the endpoint and set as the URL path. The call's arguments are protobuf-serialized and written as the POST body. The content type is set to application/x-protobuf.

On success, the response body is unmarshalled into call.Reply.

HTTP response codes which are retryable are retried with backoff in a loop using the default retry options. Other errors sending HTTP request are retried indefinitely using the same client command ID to avoid reporting failure when in fact the command may go through and execute successfully. We retry here to eventually get through with the same client command ID and be given the cached response.

func RegisterSender

func RegisterSender(scheme string, f NewSenderFunc)

RegisterSender registers the specified function to be used for creation of a new sender when the specified scheme is encountered.

Types

type AdminClient

type AdminClient struct {
	// contains filtered or unexported fields
}

AdminClient issues http requests to admin endpoints. TODO(marc): unify the way we handle addresses in clients.

func NewAdminClient

func NewAdminClient(ctx *base.Context, address, configType string) AdminClient

NewAdminClient returns a new 'configType' admin client, talking to 'address'.

func (*AdminClient) Delete

func (a *AdminClient) Delete(key string) error

Delete issues a DELETE request for the given key.

func (*AdminClient) Get

func (a *AdminClient) Get() (string, error)

Get issues a GET and returns the plain-text body. It cannot take a key.

func (*AdminClient) GetJSON

func (a *AdminClient) GetJSON(key string) (string, error)

GetJSON issues a GET request and returns a json-encoded response.

func (*AdminClient) GetYAML

func (a *AdminClient) GetYAML(key string) (string, error)

GetYAML issues a GET request and returns a yaml-encoded response.

func (*AdminClient) List

func (a *AdminClient) List() ([]string, error)

List issues a GET request to list all configs. Returns a list of keys.

func (*AdminClient) SetJSON

func (a *AdminClient) SetJSON(key, body string) error

SetJSON issues a POST request for the given key using the json-encoded body.

func (*AdminClient) SetYAML

func (a *AdminClient) SetYAML(key, body string) error

SetYAML issues a POST request for the given key using the yaml-encoded body.

type Batch

type Batch struct {
	// The DB the batch is associated with. This field may be nil if the batch
	// was not created via DB.NewBatch or Txn.NewBatch.
	DB *DB
	// Results contains an entry for each operation added to the batch. The order
	// of the results matches the order the operations were added to the
	// batch. For example:
	//
	//   b := db.NewBatch()
	//   b.Put("a", "1")
	//   b.Put("b", "2")
	//   _ = db.Run(b)
	//   // string(b.Results[0].Rows[0].Key) == "a"
	//   // string(b.Results[1].Rows[0].Key) == "b"
	Results []Result
	// contains filtered or unexported fields
}

Batch provides for the parallel execution of a number of database operations. Operations are added to the Batch and then the Batch is executed via either DB.Run, Txn.Run or Txn.Commit.

TODO(pmattis): Allow a timestamp to be specified which is applied to all operations within the batch.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	b := &client.Batch{}
	b.Get("aa")
	b.Put("bb", "2")
	if err := db.Run(b); err != nil {
		panic(err)
	}
	for _, result := range b.Results {
		for _, row := range result.Rows {
			fmt.Printf("%s=%s\n", row.Key, row.ValueBytes())
		}
	}

}
Output:

aa=
bb=2

func (*Batch) CPut

func (b *Batch) CPut(key, value, expValue interface{})

CPut conditionally sets the value for a key if the existing value is equal to expValue. To conditionally set a value only if there is no existing entry pass nil for expValue.

A new result will be appended to the batch which will contain a single row and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

func (*Batch) Del

func (b *Batch) Del(keys ...interface{})

Del deletes one or more keys.

A new result will be appended to the batch and each key will have a corresponding row in the returned Result.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) DelRange

func (b *Batch) DelRange(s, e interface{})

DelRange deletes the rows between begin (inclusive) and end (exclusive).

A new result will be appended to the batch which will contain 0 rows and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) Get

func (b *Batch) Get(key interface{})

Get retrieves the value for a key. A new result will be appended to the batch which will contain a single row.

r, err := db.Get("a")
// string(r.Rows[0].Key) == "a"

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) GetProto

func (b *Batch) GetProto(key interface{}, msg gogoproto.Message)

GetProto retrieves the value for a key and decodes the result as a proto message. A new result will be appended to the batch which will contain a single row. Note that the proto will not be decoded until after the batch is executed using DB.Run or Txn.Run.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) Inc

func (b *Batch) Inc(key interface{}, value int64)

Inc increments the integer value at key. If the key does not exist it will be created with an initial value of 0 which will then be incremented. If the key exists but was set using Put or CPut an error will be returned.

A new result will be appended to the batch which will contain a single row and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) InternalAddCall

func (b *Batch) InternalAddCall(call proto.Call)

InternalAddCall adds the specified call to the batch. It is intended for internal use only.

func (*Batch) Put

func (b *Batch) Put(key, value interface{})

Put sets the value for a key.

A new result will be appended to the batch which will contain a single row and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

func (*Batch) ReverseScan

func (b *Batch) ReverseScan(s, e interface{}, maxRows int64)

ReverseScan retrieves the rows between begin (inclusive) and end (exclusive) in descending order.

A new result will be appended to the batch which will contain up to maxRows rows and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Batch) Scan

func (b *Batch) Scan(s, e interface{}, maxRows int64)

Scan retrieves the rows between begin (inclusive) and end (exclusive) in ascending order.

A new result will be appended to the batch which will contain up to maxRows rows and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

type DB

type DB struct {
	Sender Sender
	// contains filtered or unexported fields
}

DB is a database handle to a single cockroach cluster. A DB is safe for concurrent use by multiple goroutines.

func Open

func Open(addr string, opts ...Option) (*DB, error)

Open creates a new database handle to the cockroach cluster specified by addr. The cluster is identified by a URL with the format:

[<sender>:]//[<user>@]<host>:<port>[?certs=<dir>,priority=<val>]

The URL scheme (<sender>) specifies which transport to use for talking to the cockroach cluster. Currently allowable values are: http, https, rpc, rpcs. The rpc and rpcs senders use a variant of Go's builtin rpc library for communication with the cluster. This protocol is lower overhead and more efficient than http. The decision between the encrypted (https, rpcs) and unencrypted senders (http, rpc) depends on the settings of the cluster. A given cluster supports either encrypted or unencrypted traffic, but not both. The <sender> can be left unspecified in the URL and set by passing client.SenderOpt.

If not specified, the <user> field defaults to "root".

The certs parameter can be used to override the default directory to use for client certificates. In tests, the directory "test_certs" uses the embedded test certificates.

The priority parameter can be used to override the default priority for operations.

func (*DB) AdminMerge

func (db *DB) AdminMerge(key interface{}) error

AdminMerge merges the range containing key and the subsequent range. After the merge operation is complete, the range containing key will contain all of the key/value pairs of the subsequent range and the subsequent range will no longer exist.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*DB) AdminSplit

func (db *DB) AdminSplit(splitKey interface{}) error

AdminSplit splits the range at splitkey.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*DB) CPut

func (db *DB) CPut(key, value, expValue interface{}) error

CPut conditionally sets the value for a key if the existing value is equal to expValue. To conditionally set a value only if there is no existing entry pass nil for expValue.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	if err := db.Put("aa", "1"); err != nil {
		panic(err)
	}
	if err := db.CPut("aa", "2", "1"); err != nil {
		panic(err)
	}
	result, err := db.Get("aa")
	if err != nil {
		panic(err)
	}
	fmt.Printf("aa=%s\n", result.ValueBytes())

	if err = db.CPut("aa", "3", "1"); err == nil {
		panic("expected error from conditional put")
	}
	result, err = db.Get("aa")
	if err != nil {
		panic(err)
	}
	fmt.Printf("aa=%s\n", result.ValueBytes())

	if err = db.CPut("bb", "4", "1"); err == nil {
		panic("expected error from conditional put")
	}
	result, err = db.Get("bb")
	if err != nil {
		panic(err)
	}
	fmt.Printf("bb=%s\n", result.ValueBytes())
	if err = db.CPut("bb", "4", nil); err != nil {
		panic(err)
	}
	result, err = db.Get("bb")
	if err != nil {
		panic(err)
	}
	fmt.Printf("bb=%s\n", result.ValueBytes())

}
Output:

aa=2
aa=2
bb=
bb=4

func (*DB) Del

func (db *DB) Del(keys ...interface{}) error

Del deletes one or more keys.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	b := &client.Batch{}
	b.Put("aa", "1")
	b.Put("ab", "2")
	b.Put("ac", "3")
	if err := db.Run(b); err != nil {
		panic(err)
	}
	if err := db.Del("ab"); err != nil {
		panic(err)
	}
	rows, err := db.Scan("a", "b", 100)
	if err != nil {
		panic(err)
	}
	for i, row := range rows {
		fmt.Printf("%d: %s=%s\n", i, row.Key, row.ValueBytes())
	}

}
Output:

0: aa=1
1: ac=3

func (*DB) DelRange

func (db *DB) DelRange(begin, end interface{}) error

DelRange deletes the rows between begin (inclusive) and end (exclusive).

TODO(pmattis): Perhaps the result should return which rows were deleted.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*DB) Get

func (db *DB) Get(key interface{}) (KeyValue, error)

Get retrieves the value for a key, returning the retrieved key/value or an error.

r, err := db.Get("a")
// string(r.Key) == "a"

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	result, err := db.Get("aa")
	if err != nil {
		panic(err)
	}
	fmt.Printf("aa=%s\n", result.ValueBytes())

}
Output:

aa=

func (*DB) GetProto

func (db *DB) GetProto(key interface{}, msg gogoproto.Message) error

GetProto retrieves the value for a key and decodes the result as a proto message.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*DB) Inc

func (db *DB) Inc(key interface{}, value int64) (KeyValue, error)

Inc increments the integer value at key. If the key does not exist it will be created with an initial value of 0 which will then be incremented. If the key exists but was set using Put or CPut an error will be returned.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	if _, err := db.Inc("aa", 100); err != nil {
		panic(err)
	}
	result, err := db.Get("aa")
	if err != nil {
		panic(err)
	}
	fmt.Printf("aa=%d\n", result.ValueInt())

}
Output:

aa=100

func (*DB) NewBatch

func (db *DB) NewBatch() *Batch

NewBatch creates and returns a new empty batch object for use with the DB.

func (*DB) Put

func (db *DB) Put(key, value interface{}) error

Put sets the value for a key.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	if err := db.Put("aa", "1"); err != nil {
		panic(err)
	}
	result, err := db.Get("aa")
	if err != nil {
		panic(err)
	}
	fmt.Printf("aa=%s\n", result.ValueBytes())

}
Output:

aa=1

func (*DB) ReverseScan

func (db *DB) ReverseScan(begin, end interface{}, maxRows int64) ([]KeyValue, error)

ReverseScan retrieves the rows between begin (inclusive) and end (exclusive) in descending order.

The returned []KeyValue will contain up to maxRows elements.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	b := &client.Batch{}
	b.Put("aa", "1")
	b.Put("ab", "2")
	b.Put("bb", "3")
	if err := db.Run(b); err != nil {
		panic(err)
	}
	rows, err := db.ReverseScan("ab", "c", 100)
	if err != nil {
		panic(err)
	}
	for i, row := range rows {
		fmt.Printf("%d: %s=%s\n", i, row.Key, row.ValueBytes())
	}

}
Output:

0: bb=3
1: ab=2

func (*DB) Run

func (db *DB) Run(b *Batch) error

Run executes the operations queued up within a batch. Before executing any of the operations the batch is first checked to see if there were any errors during its construction (e.g. failure to marshal a proto message).

The operations within a batch are run in parallel and the order is non-deterministic. It is an unspecified behavior to modify and retrieve the same key within a batch.

Upon completion, Batch.Results will contain the results for each operation. The order of the results matches the order the operations were added to the batch.

func (*DB) Scan

func (db *DB) Scan(begin, end interface{}, maxRows int64) ([]KeyValue, error)

Scan retrieves the rows between begin (inclusive) and end (exclusive) in ascending order.

The returned []KeyValue will contain up to maxRows elements.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

Example
package main

import (
	"fmt"
	"log"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/server"
)

func setup() (*server.TestServer, *client.DB) {
	s := server.StartTestServer(nil)
	db, err := client.Open("https://root@" + s.ServingAddr() + "?certs=test_certs")
	if err != nil {
		log.Fatal(err)
	}
	return s, db
}

func main() {
	s, db := setup()
	defer s.Stop()

	b := &client.Batch{}
	b.Put("aa", "1")
	b.Put("ab", "2")
	b.Put("bb", "3")
	if err := db.Run(b); err != nil {
		panic(err)
	}
	rows, err := db.Scan("a", "b", 100)
	if err != nil {
		panic(err)
	}
	for i, row := range rows {
		fmt.Printf("%d: %s=%s\n", i, row.Key, row.ValueBytes())
	}

}
Output:

0: aa=1
1: ab=2

func (*DB) Txn

func (db *DB) Txn(retryable func(txn *Txn) error) error

Txn executes retryable in the context of a distributed transaction. The transaction is automatically aborted if retryable returns any error aside from recoverable internal errors, and is automatically committed otherwise. The retryable function should have no side effects which could cause problems in the event it must be run more than once.

TODO(pmattis): Allow transaction options to be specified.

type KeyValue

type KeyValue struct {
	Key       []byte
	Value     interface{}
	Timestamp time.Time
}

KeyValue represents a single key/value pair and corresponding timestamp.

func (*KeyValue) Exists

func (kv *KeyValue) Exists() bool

Exists returns true iff the value exists.

func (*KeyValue) String

func (kv *KeyValue) String() string

func (*KeyValue) ValueBytes

func (kv *KeyValue) ValueBytes() []byte

ValueBytes returns the value as a byte slice. This method will panic if the value's type is not a byte slice.

func (*KeyValue) ValueInt

func (kv *KeyValue) ValueInt() int64

ValueInt returns the value decoded as an int64. This method will panic if the value cannot be decoded as an int64.

func (*KeyValue) ValueProto

func (kv *KeyValue) ValueProto(msg gogoproto.Message) error

ValueProto parses the byte slice value as a proto message.

type NewSenderFunc

type NewSenderFunc func(u *url.URL, ctx *base.Context, retryOpts retry.Options) (Sender, error)

NewSenderFunc creates a new sender for the registered scheme.

type Option

type Option func(*DB)

Option is the signature for a function which applies an option to a DB.

func SenderOpt

func SenderOpt(sender Sender) Option

SenderOpt sets the sender for a DB.

type PostContext

type PostContext struct {
	Server    string // The host:port address of the Cockroach gateway node
	Endpoint  string
	Context   *base.Context // The base context: needed for client setup.
	RetryOpts retry.Options
}

PostContext is the context passed into the Post function

type Result

type Result struct {

	// Err contains any error encountered when performing the operation.
	Err error
	// Rows contains the key/value pairs for the operation. The number of rows
	// returned varies by operation. For Get, Put, CPut, Inc and Del the number
	// of rows returned is the number of keys operated on. For Scan the number of
	// rows returned is the number or rows matching the scan capped by the
	// maxRows parameter. For DelRange Rows is nil.
	Rows []KeyValue
	// contains filtered or unexported fields
}

Result holds the result for a single DB or Txn operation (e.g. Get, Put, etc).

func (Result) String

func (r Result) String() string

type Runner

type Runner interface {
	Run(b *Batch) error
}

Runner only exports the Run method on a batch of operations.

type Sender

type Sender interface {
	// Send invokes the Call.Method with Call.Args and sets the result
	// in Call.Reply.
	Send(context.Context, proto.Call)
}

Sender is an interface for sending a request to a Key-Value database backend.

type SenderFunc

type SenderFunc func(context.Context, proto.Call)

SenderFunc is an adapter to allow the use of ordinary functions as Senders.

func (SenderFunc) Send

func (f SenderFunc) Send(ctx context.Context, c proto.Call)

Send calls f(ctx, c).

type Txn

type Txn struct {
	// contains filtered or unexported fields
}

Txn is an in-progress distributed database transaction. A Txn is not safe for concurrent use by multiple goroutines.

func (*Txn) CPut

func (txn *Txn) CPut(key, value, expValue interface{}) error

CPut conditionally sets the value for a key if the existing value is equal to expValue. To conditionally set a value only if there is no existing entry pass nil for expValue.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

func (*Txn) Commit

func (txn *Txn) Commit() error

Commit sends an EndTransactionRequest with Commit=true.

func (*Txn) CommitInBatch

func (txn *Txn) CommitInBatch(b *Batch) error

CommitInBatch executes the operations queued up within a batch and commits the transaction. Explicitly committing a transaction is optional, but more efficient than relying on the implicit commit performed when the transaction function returns without error.

func (*Txn) DebugName

func (txn *Txn) DebugName() string

DebugName returns the debug name associated with the transaction.

func (*Txn) Del

func (txn *Txn) Del(keys ...interface{}) error

Del deletes one or more keys.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) DelRange

func (txn *Txn) DelRange(begin, end interface{}) error

DelRange deletes the rows between begin (inclusive) and end (exclusive).

The returned Result will contain 0 rows and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) Get

func (txn *Txn) Get(key interface{}) (KeyValue, error)

Get retrieves the value for a key, returning the retrieved key/value or an error.

r, err := db.Get("a")
// string(r.Key) == "a"

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) GetProto

func (txn *Txn) GetProto(key interface{}, msg gogoproto.Message) error

GetProto retrieves the value for a key and decodes the result as a proto message.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) Inc

func (txn *Txn) Inc(key interface{}, value int64) (KeyValue, error)

Inc increments the integer value at key. If the key does not exist it will be created with an initial value of 0 which will then be incremented. If the key exists but was set using Put or CPut an error will be returned.

The returned Result will contain a single row and Result.Err will indicate success or failure.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) InternalSetPriority

func (txn *Txn) InternalSetPriority(priority int32)

InternalSetPriority sets the transaction priority. It is intended for internal (testing) use only.

func (*Txn) NewBatch

func (txn *Txn) NewBatch() *Batch

NewBatch creates and returns a new empty batch object for use with the Txn.

func (*Txn) Put

func (txn *Txn) Put(key, value interface{}) error

Put sets the value for a key

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler. value can be any key type or a proto.Message.

func (*Txn) ReverseScan

func (txn *Txn) ReverseScan(begin, end interface{}, maxRows int64) ([]KeyValue, error)

ReverseScan retrieves the rows between begin (inclusive) and end (exclusive) in descending order.

The returned []KeyValue will contain up to maxRows elements.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) Rollback

func (txn *Txn) Rollback() error

Rollback sends an EndTransactionRequest with Commit=false.

func (*Txn) Run

func (txn *Txn) Run(b *Batch) error

Run executes the operations queued up within a batch. Before executing any of the operations the batch is first checked to see if there were any errors during its construction (e.g. failure to marshal a proto message).

The operations within a batch are run in parallel and the order is non-deterministic. It is an unspecified behavior to modify and retrieve the same key within a batch.

Upon completion, Batch.Results will contain the results for each operation. The order of the results matches the order the operations were added to the batch.

func (*Txn) Scan

func (txn *Txn) Scan(begin, end interface{}, maxRows int64) ([]KeyValue, error)

Scan retrieves the rows between begin (inclusive) and end (exclusive) in ascending order.

The returned []KeyValue will contain up to maxRows elements.

key can be either a byte slice, a string, a fmt.Stringer or an encoding.BinaryMarshaler.

func (*Txn) SetDebugName

func (txn *Txn) SetDebugName(name string)

SetDebugName sets the debug name associated with the transaction which will appear in log files and the web UI. Each transaction starts out with an automatically assigned debug name composed of the file and line number where the transaction was created.

func (*Txn) SetSnapshotIsolation

func (txn *Txn) SetSnapshotIsolation()

SetSnapshotIsolation sets the transaction's isolation type to snapshot. Transactions default to serializable isolation. The isolation must be set before any operations are performed on the transaction.

TODO(pmattis): This isn't tested yet but will be as part of the conversion of client_test.go.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL