Commit 2e9d1053 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 83d4082d
// Copyright (C) 2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package lonet
// TODO test go-go
// TODO test go-py
...@@ -21,6 +21,7 @@ package lonet ...@@ -21,6 +21,7 @@ package lonet
// registry of network hosts // registry of network hosts
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
) )
...@@ -51,7 +52,7 @@ type registry interface { ...@@ -51,7 +52,7 @@ type registry interface {
// - errRegistryDown if registry cannot be accessed XXX (and its underlying cause?) // - errRegistryDown if registry cannot be accessed XXX (and its underlying cause?)
// - errHostDup // - errHostDup
// - some other error indicating e.g. IO problem. // - some other error indicating e.g. IO problem.
Announce(hostname, osladdr string) error Announce(ctx context.Context, hostname, osladdr string) error
// Query queries registry for host. // Query queries registry for host.
// //
...@@ -64,7 +65,14 @@ type registry interface { ...@@ -64,7 +65,14 @@ type registry interface {
// - errRegistryDown ... XXX // - errRegistryDown ... 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(hostname string) (osladdr string, _ error) Query(ctx context.Context, hostname string) (osladdr string, _ error)
// Close closes access to registry.
//
// Close interrupts all in-fligh Announce and Query requests started
// via closed registry connection. Those interrupted requests will
// return with errRegistryDown error cause.
Close() error
} }
var errRegistryDown = errors.New("registry is down") var errRegistryDown = errors.New("registry is down")
...@@ -72,7 +80,7 @@ var errNoHost = errors.New("no such host") ...@@ -72,7 +80,7 @@ var errNoHost = errors.New("no such host")
var errHostDup = errors.New("host already registered") var errHostDup = errors.New("host already registered")
type registryError struct { type registryError struct {
// XXX name of the network? // XXX name of the network? - XXX yes
Registry string // name of the registry Registry string // name of the registry
Op string // operation that failed Op string // operation that failed
Args interface{} // operation arguments, if any Args interface{} // operation arguments, if any
......
...@@ -19,3 +19,145 @@ ...@@ -19,3 +19,145 @@
package lonet package lonet
// registry implemented as shared SQLite file // registry implemented as shared SQLite file
import (
"context"
"crawshaw.io/sqlite"
"crawshaw.io/sqlite/sqliteutil"
)
// registry schema
//
// hosts:
// hostname text !null PK
// osladdr text !null
//
// meta:
// name text !null PK
// value text !null
//
// "schemaver" str(int) - version of schema.
// "network" text - name of lonet network this registry serves.
type sqliteRegistry struct {
dbpool *sqlite.Pool
uri string // URI db was originally opened with
}
// openRegistrySqlite opens SQLite registry located at dburi.
// XXX network name?
func openRegistrySQLite(dburi string) (_ *sqliteRegistry, err error) {
r := &sqliteRegistry{uri: dburi}
defer r.regerr(&err, "open")
dbpool, err := sqlite.Open(dburi, 0, /* poolSize= */16) // XXX pool size ok?
if err != nil {
return nil, err
}
r.dbpool = dbpool
return r, nil
// XXX setup
}
func (r *sqliteRegistry) Close() (err error) {
defer r.regerr(&err, "close")
return r.dbpool.Close()
}
func (r *sqliteRegistry) setup(ctx context.Context) (err error) {
defer r.regerr(&err, "setup") // XXX args?
// XXX get conn
var conn *sqlite.Conn
err = sqliteutil.ExecScript(conn, `
CREATE TABLE IF NOT EXISTS hosts (
hostname TEXT NON NULL PRIMARY KEY,
osladdr TEXT NON NULL
);
CREATE TABLE IF NOT EXISTS meta (
name TEXT NON NULL PRIMARY KEY,
value TEXT NON NULL
);
`)
if err != nil {
return err
}
// XXX check schemaver
// XXX check network name
return nil
}
func (r *sqliteRegistry) Announce(ctx context.Context, hostname, osladdr string) (err error) {
defer r.regerr(&err, "announce", hostname, osladdr)
conn := r.dbpool.Get(ctx.Done())
if conn == nil {
// either ctx cancel or dbpool close
if ctx.Err() != nil {
return ctx.Err()
}
return errRegistryDown // db closed
}
defer r.dbpool.Put(conn)
//sqliteutil.Exec(conn, "SELECT hostname, osladdr FROM hosts WHERE hostname = ?", func (stmt *sqlite.Stmt) error {
err = sqliteutil.Exec(conn, "INSERT INTO hosts (hostname, osladdr) VALUES (?, ?)", nil, hostname, osladdr)
// XXX -> errNoHost
switch sqlite.ErrCode(err) {
case sqlite.SQLITE_CONSTRAINT_UNIQUE: // XXX test
err = errHostDup
}
return err
}
func (r *sqliteRegistry) Query(ctx context.Context, hostname string) (osladdr string, err error) {
defer r.regerr(&err, "query", hostname)
// XXX get conn
var conn *sqlite.Conn
err = sqliteutil.Exec(conn, "SELECT osladdr FROM hosts WHERE hostname = ?", func (stmt *sqlite.Stmt) error {
osladdr = stmt.ColumnText(0)
return nil
})
/* XXX reenable
switch sqlite.ErrCode(err) {
case sqlite.XXXNOROW:
err = errNoHost
}
*/
/*
if err != nil {
return "", err
}
*/
return osladdr, err
}
// regerr is syntatic sugar to wrap !nil *errp into registryError.
func (r *sqliteRegistry) regerr(errp *error, op string, args ...interface{}) {
if *errp == nil {
return
}
// XXX name of the network
*errp = &registryError{
Registry: r.uri,
Op: op,
Args: args,
Err: *errp,
}
}
// Copyright (C) 2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package lonet
import (
"io/ioutil"
"os"
"testing"
"lab.nexedi.com/kirr/go123/exc"
)
func TestRegistrySQLite(t *testing.T) {
X := exc.Raiseif
work, err := ioutil.TempDir("", "t-registry-sqlite")
X(err)
defer os.RemoveAll(work)
dbpath := work + "/1.db"
r, err := openRegistrySQLite(dbpath)
X(err)
// r.Network() == ...
// r.Query("α") == ø
// r.Announce("α", "alpha:1234")
// r.Query("α") == "alpha:1234")
// r.Query("β") == ø
r2, err := openRegistrySQLite(dbpath)
// r2.Network() == ...
// r2.Query("α") == "alpha:1234"
// r2.Query("β") == ø
// r2.Announce("β", "beta:zzz")
// r2.Query("β") == "beta:zzz")
// r.Query("β") == "beta:zzz")
X(r.Close())
// r.Query("α") == errRegistryDown
// r.Query("β") == errRegistryDown
// r.Announce("γ", "gamma:qqq") == errRegistryDown
// r.Query("γ") == errRegistryDown
X(r2.Close())
}
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