nap

package module
v0.0.0-...-db51f95 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2024 License: MIT Imports: 6 Imported by: 0

README

Nap

Note Segment has paused maintenance on this project, but may return it to an active status in the future. Issues and pull requests from external contributors are not being considered, although internal contributions may appear from time to time. The project remains available under its open source license for anyone to use.

Nap is a library that abstracts access to primary-replica physical SQL servers topologies as a single logical database mimicking the standard sql.DB APIs.

Install

$ go get github.com/tsenart/nap

Usage

package main

import (
  "log"

  "github.com/tsenart/nap"
  _ "github.com/go-sql-driver/mysql" // Any sql.DB works
)

func main() {
  // The first DSN is assumed to be the primary and all
  // other to be replicas
  dsns := "tcp://user:password@primary/dbname;"
  dsns += "tcp://user:password@replica01/dbname;"
  dsns += "tcp://user:password@replica02/dbname"

  db, err := nap.Open("mysql", dsns)
  if err != nil {
    log.Fatal(err)
  }

  if err := db.Ping(); err != nil {
    log.Fatalf("Some physical database is unreachable: %s", err)
  }

  // Read queries are directed to replicas with Query and QueryRow.
  // Always use Query or QueryRow for SELECTS
  // Load distribution is round-robin only for now.
  var count int
  err = db.QueryRow("SELECT COUNT(*) FROM sometable").Scan(&count)
  if err != nil {
    log.Fatal(err)
  }

  // Write queries are directed to the primary with Exec.
  // Always use Exec for INSERTS, UPDATES
  err = db.Exec("UPDATE sometable SET something = 1")
  if err != nil {
    log.Fatal(err)
  }

  // Prepared statements are aggregates. If any of the underlying
  // physical databases fails to prepare the statement, the call will
  // return an error. On success, if Exec is called, then the
  // primary is used, if Query or QueryRow are called, then a replica
  // is used.
  stmt, err := db.Prepare("SELECT * FROM sometable WHERE something = ?")
  if err != nil {
    log.Fatal(err)
  }

  // Transactions always use the primary
  tx, err := db.Begin()
  if err != nil {
    log.Fatal(err)
  }
  // Do something transactional ...
  if err = tx.Commit(); err != nil {
    log.Fatal(err)
  }

  // If needed, one can access the primary or a replica explicitly.
  primary, replica := db.Primary(), db.Replica()
}

Todo

  • Support other replica load balancing algorithms.

License

See LICENSE

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DB

type DB struct {
	Pdbs []SQLDB // Physical databases
	// contains filtered or unexported fields
}

DB is a logical database with multiple underlying physical databases forming a single primary, multiple replicas topology. Reads and writes are automatically directed to the correct physical db.

func Open

func Open(driverName, dataSourceNames string) (*DB, error)

Open concurrently opens each underlying physical db. dataSourceNames must be a semi-comma separated list of DSNs with the first one being used as the primary and the rest as replicas.

func (*DB) Begin

func (db *DB) Begin() (*sql.Tx, error)

Begin starts a transaction on the primary. The isolation level is dependent on the driver.

func (*DB) BeginTx

func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)

Begin starts a transaction with the provided context on the primary. The isolation level is dependent on the driver.

func (*DB) Close

func (db *DB) Close() error

Close closes all physical databases concurrently, releasing any open resources.

func (*DB) Driver

func (db *DB) Driver() driver.Driver

Driver returns the physical database's underlying driver.

func (*DB) Exec

func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error)

Exec executes a query without returning any rows. The args are for any placeholder parameters in the query. Exec uses the primary as the underlying physical db.

func (*DB) ExecContext

func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

ExecContext executes a query without returning any rows. The args are for any placeholder parameters in the query. Exec uses the primary as the underlying physical db.

func (*DB) Master deprecated

func (db *DB) Master() SQLDB

Master returns the primary physical database

Deprecated: use db.Primary instead.

func (*DB) Ping

func (db *DB) Ping() error

Ping verifies if a connection to each physical database is still alive, establishing a connection if necessary.

func (*DB) PingContext

func (db *DB) PingContext(ctx context.Context) error

PingContext verifies if a connection to each physical database is still alive, establishing a connection if necessary.

func (*DB) Prepare

func (db *DB) Prepare(query string) (Stmt, error)

Prepare creates a prepared statement for later queries or executions on each physical database, concurrently.

func (*DB) PrepareContext

func (db *DB) PrepareContext(ctx context.Context, query string) (Stmt, error)

PrepareContext creates a prepared statement for later queries or executions on each physical database, concurrently.

The provided context is used for the preparation of the statement, not for the execution of the statement.

func (*DB) Primary

func (db *DB) Primary() SQLDB

func (*DB) Query

func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error)

Query executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query. Query uses a replica as the physical db.

func (*DB) QueryContext

func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

QueryContext executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query. QueryContext uses a replica as the physical db.

func (*DB) QueryRow

func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row

QueryRow executes a query that is expected to return at most one row. QueryRow always return a non-nil value. Errors are deferred until Row's Scan method is called. QueryRow uses a replica as the physical db.

func (*DB) QueryRowContext

func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row

QueryRowContext executes a query that is expected to return at most one row. QueryRowContext always return a non-nil value. Errors are deferred until Row's Scan method is called. QueryRowContext uses a replica as the physical db.

func (*DB) Replica

func (db *DB) Replica() SQLDB

func (*DB) SetConnMaxLifetime

func (db *DB) SetConnMaxLifetime(d time.Duration)

SetConnMaxLifetime sets the maximum amount of time a connection may be reused. Expired connections may be closed lazily before reuse. If d <= 0, connections are reused forever.

func (*DB) SetMaxIdleConns

func (db *DB) SetMaxIdleConns(n int)

SetMaxIdleConns sets the maximum number of connections in the idle connection pool for each underlying physical db. If MaxOpenConns is greater than 0 but less than the new MaxIdleConns then the new MaxIdleConns will be reduced to match the MaxOpenConns limit If n <= 0, no idle connections are retained.

func (*DB) SetMaxOpenConns

func (db *DB) SetMaxOpenConns(n int)

SetMaxOpenConns sets the maximum number of open connections to each physical database. If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than MaxIdleConns, then MaxIdleConns will be reduced to match the new MaxOpenConns limit. If n <= 0, then there is no limit on the number of open connections. The default is 0 (unlimited).

func (*DB) Slave deprecated

func (db *DB) Slave() SQLDB

Slave returns one of the physical databases which is a replica

Deprecated: use db.Replica instead

type SQLDB

type SQLDB interface {
	Close() error
	Driver() driver.Driver
	Begin() (*sql.Tx, error)
	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
	Exec(query string, args ...interface{}) (sql.Result, error)
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
	Ping() error
	PingContext(ctx context.Context) error
	Prepare(query string) (*sql.Stmt, error)
	PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	QueryRow(query string, args ...interface{}) *sql.Row
	QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
	SetConnMaxLifetime(d time.Duration)
	SetMaxIdleConns(n int)
	SetMaxOpenConns(n int)
}

type Stmt

type Stmt interface {
	Close() error
	Exec(...interface{}) (sql.Result, error)
	Query(...interface{}) (*sql.Rows, error)
	QueryRow(...interface{}) *sql.Row
}

Stmt is an aggregate prepared statement. It holds a prepared statement for each underlying physical db.

Jump to

Keyboard shortcuts

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