Commit 1f33a2f0 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent f80241b8
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package lonet package lonet
// registry of network hosts // registry of network hosts.
import ( import (
"context" "context"
...@@ -51,8 +51,8 @@ type registry interface { ...@@ -51,8 +51,8 @@ type registry interface {
// Returned error, if !nil, is *registryError with .Err describing the // Returned error, if !nil, is *registryError with .Err describing the
// error cause: // error cause:
// //
// - errRegistryDown if registry cannot be accessed XXX (and its underlying cause?) // - errRegistryDown if registry cannot be accessed, XXX (and its underlying cause?)
// - errHostDup // - errHostDup if hostname was already announced,
// - some other error indicating e.g. IO problem. // - some other error indicating e.g. IO problem.
Announce(ctx context.Context, hostname, osladdr string) error Announce(ctx context.Context, hostname, osladdr string) error
...@@ -64,15 +64,15 @@ type registry interface { ...@@ -64,15 +64,15 @@ type registry interface {
// Returned error, if !nil, is *registryError with .Err describing the // Returned error, if !nil, is *registryError with .Err describing the
// error cause: // error cause:
// //
// - errRegistryDown ... XXX // - errRegistryDown if registry cannot be accessed, XXX ^^^
// - errNoHost if hostname was not announced to registry, // - errNoHost if hostname was not announced to registry,
// - some other error indicating e.g. IO problem. // - some other error indicating e.g. IO problem.
Query(ctx context.Context, hostname string) (osladdr string, _ error) Query(ctx context.Context, hostname string) (osladdr string, _ error)
// Close closes access to registry. // Close closes access to registry.
// //
// Close interrupts all in-fligh Announce and Query requests started // Close interrupts all in-flight Announce and Query requests started
// via closed registry connection. Those interrupted requests will // via closing registry connection. Those interrupted requests will
// return with errRegistryDown error cause. // return with errRegistryDown error cause.
Close() error Close() error
} }
...@@ -81,6 +81,7 @@ var errRegistryDown = errors.New("registry is down") ...@@ -81,6 +81,7 @@ var errRegistryDown = errors.New("registry is down")
var errNoHost = errors.New("no such host") var errNoHost = errors.New("no such host")
var errHostDup = errors.New("host already registered") var errHostDup = errors.New("host already registered")
// registryError represents an error of a registry operation.
type registryError struct { type registryError struct {
// XXX name of the network? - XXX yes // XXX name of the network? - XXX yes
Registry string // name of the registry Registry string // name of the registry
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package lonet package lonet
// registry implemented as shared SQLite file // registry implemented as shared SQLite file.
import ( import (
"context" "context"
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
"lab.nexedi.com/kirr/go123/xerr" "lab.nexedi.com/kirr/go123/xerr"
) )
// registry schema // registry schema (keep in sync wrt .setup())
// //
// hosts: // hosts:
// hostname text !null PK // hostname text !null PK
...@@ -41,7 +41,7 @@ import ( ...@@ -41,7 +41,7 @@ import (
// name text !null PK // name text !null PK
// value text !null // value text !null
// //
// "schemaver" str(int) - version of schema. // "schemaver" text - version of db schema.
// "network" text - name of lonet network this registry serves. // "network" text - name of lonet network this registry serves.
const schemaVer = "lonet.1" const schemaVer = "lonet.1"
...@@ -52,7 +52,7 @@ type sqliteRegistry struct { ...@@ -52,7 +52,7 @@ type sqliteRegistry struct {
uri string // URI db was originally opened with uri string // URI db was originally opened with
} }
// openRegistrySqlite opens SQLite registry located at dburi. // openRegistrySQLite opens SQLite registry located at dburi.
// //
// the registry is setup/verified to be serving specified lonet network. // the registry is setup/verified to be serving specified lonet network.
func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRegistry, err error) { func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRegistry, err error) {
...@@ -66,6 +66,7 @@ func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRe ...@@ -66,6 +66,7 @@ func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRe
r.dbpool = dbpool r.dbpool = dbpool
// initialize/check db
err = r.setup(ctx, network) err = r.setup(ctx, network)
if err != nil { if err != nil {
r.Close() r.Close()
...@@ -75,6 +76,7 @@ func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRe ...@@ -75,6 +76,7 @@ func openRegistrySQLite(ctx context.Context, dburi, network string) (_ *sqliteRe
return r, nil return r, nil
} }
// Close implements registry.
func (r *sqliteRegistry) Close() (err error) { func (r *sqliteRegistry) Close() (err error) {
defer r.regerr(&err, "close") defer r.regerr(&err, "close")
return r.dbpool.Close() return r.dbpool.Close()
...@@ -122,8 +124,12 @@ func query1(conn *sqlite.Conn, query string, resultf func(stmt *sqlite.Stmt), ar ...@@ -122,8 +124,12 @@ func query1(conn *sqlite.Conn, query string, resultf func(stmt *sqlite.Stmt), ar
return nil return nil
} }
func (r *sqliteRegistry) setup(ctx context.Context, network string) error { // setup initializes/checks registry database to be of expected schema and configuration.
func (r *sqliteRegistry) setup(ctx context.Context, network string) (err error) {
defer xerr.Contextf(&err, "setup %q", network)
return r.withConn(ctx, func(conn *sqlite.Conn) (err error) { return r.withConn(ctx, func(conn *sqlite.Conn) (err error) {
// NOTE: keep in sync wrt top-level text.
err = sqliteutil.ExecScript(conn, ` err = sqliteutil.ExecScript(conn, `
CREATE TABLE IF NOT EXISTS hosts ( CREATE TABLE IF NOT EXISTS hosts (
hostname TEXT NON NULL PRIMARY KEY, hostname TEXT NON NULL PRIMARY KEY,
...@@ -139,11 +145,10 @@ func (r *sqliteRegistry) setup(ctx context.Context, network string) error { ...@@ -139,11 +145,10 @@ func (r *sqliteRegistry) setup(ctx context.Context, network string) error {
return err return err
} }
// do check/init under transaction // do whole checks/init under transaction, so that there is
// e.g. no race wrt another process setting config.
defer sqliteutil.Save(conn)(&err) defer sqliteutil.Save(conn)(&err)
// XXX vvv review error handling
// check/init schema version // check/init schema version
ver, err := r.config(conn, "schemaver") ver, err := r.config(conn, "schemaver")
if err != nil { if err != nil {
...@@ -183,7 +188,7 @@ func (r *sqliteRegistry) setup(ctx context.Context, network string) error { ...@@ -183,7 +188,7 @@ func (r *sqliteRegistry) setup(ctx context.Context, network string) error {
// config gets one registry configuration value by name. // config gets one registry configuration value by name.
// //
// if there is no record corresponding to name ("", nil) is returned. // if there is no record corresponding to name - ("", nil) is returned.
// XXX add ok ret to indicate presence of value? // XXX add ok ret to indicate presence of value?
func (r *sqliteRegistry) config(conn *sqlite.Conn, name string) (value string, err error) { func (r *sqliteRegistry) config(conn *sqlite.Conn, name string) (value string, err error) {
defer xerr.Contextf(&err, "config: get %q", name) defer xerr.Contextf(&err, "config: get %q", name)
...@@ -212,6 +217,7 @@ func (r *sqliteRegistry) setConfig(conn *sqlite.Conn, name, value string) (err e ...@@ -212,6 +217,7 @@ func (r *sqliteRegistry) setConfig(conn *sqlite.Conn, name, value string) (err e
return err return err
} }
// Announce implements registry.
func (r *sqliteRegistry) Announce(ctx context.Context, hostname, osladdr string) (err error) { func (r *sqliteRegistry) Announce(ctx context.Context, hostname, osladdr string) (err error) {
defer r.regerr(&err, "announce", hostname, osladdr) defer r.regerr(&err, "announce", hostname, osladdr)
...@@ -231,6 +237,7 @@ func (r *sqliteRegistry) Announce(ctx context.Context, hostname, osladdr string) ...@@ -231,6 +237,7 @@ func (r *sqliteRegistry) Announce(ctx context.Context, hostname, osladdr string)
var errRegDup = errors.New("registry broken: duplicate host entries") var errRegDup = errors.New("registry broken: duplicate host entries")
// Query implements registry.
func (r *sqliteRegistry) Query(ctx context.Context, hostname string) (osladdr string, err error) { func (r *sqliteRegistry) Query(ctx context.Context, hostname string) (osladdr string, err error) {
defer r.regerr(&err, "query", hostname) defer r.regerr(&err, "query", hostname)
...@@ -257,6 +264,10 @@ func (r *sqliteRegistry) Query(ctx context.Context, hostname string) (osladdr st ...@@ -257,6 +264,10 @@ func (r *sqliteRegistry) Query(ctx context.Context, hostname string) (osladdr st
} }
// regerr is syntactic sugar to wrap !nil *errp into registryError. // regerr is syntactic sugar to wrap !nil *errp into registryError.
//
// intended too be used like
//
// defer r.regerr(&err, "operation", arg1, arg2, ...)
func (r *sqliteRegistry) regerr(errp *error, op string, args ...interface{}) { func (r *sqliteRegistry) regerr(errp *error, op string, args ...interface{}) {
if *errp == nil { if *errp == nil {
return return
......
...@@ -141,7 +141,7 @@ func TestRegistrySQLite(t *testing.T) { ...@@ -141,7 +141,7 @@ func TestRegistrySQLite(t *testing.T) {
if !(r3 == nil && err != nil) { if !(r3 == nil && err != nil) {
t.Fatalf("network mismatch: not detected") t.Fatalf("network mismatch: not detected")
} }
errWant := fmt.Sprintf(`%s: open []: network name mismatch: want "bbb"; have "aaa"`, dbpath) errWant := fmt.Sprintf(`%s: open []: setup "bbb": network name mismatch: want "bbb"; have "aaa"`, dbpath)
if err.Error() != errWant { if err.Error() != errWant {
t.Fatalf("network mismatch: error:\nhave: %q\nwant: %q", err.Error(), errWant) t.Fatalf("network mismatch: error:\nhave: %q\nwant: %q", err.Error(), errWant)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment