Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling with gccgo? #160

Closed
ardhipoetra opened this issue Oct 6, 2021 · 5 comments
Closed

Compiling with gccgo? #160

ardhipoetra opened this issue Oct 6, 2021 · 5 comments
Labels
Bug Confirmed to be a bug

Comments

@ardhipoetra
Copy link

Hi, I tried to compile the demos (on cmd/) with gccgo, but it fails with the following error :

go1: internal compiler error: in write_hash_function, at go/gofrontend/types.cc:1955
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://gcc.gnu.org/bugs/> for instructions

Some minimal working example (on a Dockerfile):

FROM golang:1.14-alpine
WORKDIR /
RUN apk add --no-cache --update gcc-go ca-certificates git dumb-init automake libtool autoconf libuv-dev lz4-dev make gcc musl-dev linux-headers

#### raft and dqlite ####
RUN git clone https://github.com/canonical/raft 
WORKDIR /raft
RUN autoreconf -i && ./configure --enable-uv --prefix=/usr  && make -j4 install
WORKDIR /
RUN apk add sqlite-dev
RUN git clone https://github.com/canonical/dqlite
WORKDIR /dqlite
RUN autoreconf -i && ./configure --prefix=/usr && make -j4 install
WORKDIR /

RUN git clone https://github.com/canonical/go-dqlite
WORKDIR /go-dqlite

ENV CGO_LDFLAGS_ALLOW="-Wl,-z,now"
RUN go build -tags libsqlite3 -compiler gccgo -buildmode=exe -gccgoflags -g ./cmd/dqlite-demo

Is gccgo supported? Or at least, is it compile-able?

@MathieuBordere
Copy link
Contributor

Hi @ardhipoetra, thanks for your question. I haven't really tried compiling with gccgo yet, I don't know if it's compiles this way. I would be happy to accept a PR that fixes any issues our project has with gccgo though.

@MathieuBordere
Copy link
Contributor

MathieuBordere commented Oct 27, 2021

@ardhipoetra do you want to take a stab at this? Otherwise I'll probably close this issue for now.

@ardhipoetra
Copy link
Author

ardhipoetra commented Oct 27, 2021

Right now I don't have proper fix nor the time to tackle this. It looks like the problem is somewhere on the bindings with the dqlite lib. Removing all the bindings (since in my case, I don't need them), is a dirty-but-working fix.

Reference : commit c6c3f4078dad56a90f6b29f9e9796828935ed9f8 in my fork.

@c032
Copy link

c032 commented Jan 29, 2023

Okay, I think the problem is caused by the alias declarations (introduced in Go 1.9).

I can successfully build if I:

  • Comment-out all alias declarations (breaking change).
    • Fix the errors caused by this (also a breaking change).
  • Change Dockerfile to use FROM golang:1.19.5-alpine3.17.

I still cannot build with the original FROM golang:1.14-alpine, but at least the error is different now.

I'm not familiar enough with go-dqlite or gccgo to confidently say this is the actual cause of the issue, or its fix. And I didn't even try the compiled program, I just stopped after the go build command succeeded.

But I hope this helps in some way.

This is the Dockerfile I'm using, slighly modified from @ardhipoetra's:

Dockerfile
FROM golang:1.19.5-alpine3.17

# This doesn't build, but the error is different.
#FROM golang:1.14-alpine

WORKDIR /
RUN apk add --no-cache --update gcc-go ca-certificates git dumb-init automake libtool autoconf libuv-dev lz4-dev make gcc musl-dev linux-headers

#### raft and dqlite ####
RUN git clone https://github.com/canonical/raft
WORKDIR /raft
RUN autoreconf -i && ./configure --enable-uv --prefix=/usr  && make -j4 install
WORKDIR /
RUN apk add sqlite-dev
RUN git clone https://github.com/canonical/dqlite
WORKDIR /dqlite
RUN autoreconf -i && ./configure --prefix=/usr && make -j4 install
WORKDIR /

RUN git clone https://github.com/canonical/go-dqlite
WORKDIR /go-dqlite

# At the moment of writing this Dockerfile, this was
# the most recent commit on `master`.
#RUN git checkout 78005e6970d56e985e46eac2b371cdc95af3d591

# This `diff.txt` is in the GitHub comment.
COPY ./diff.txt ./diff.txt
RUN git apply diff.txt

ENV CGO_LDFLAGS_ALLOW="-Wl,-z,now"
RUN go build -v -tags libsqlite3 -compiler gccgo -buildmode=exe -gccgoflags -g ./cmd/dqlite-demo

The diff.txt mentioned in the Dockerfile (these are breaking changes):

diff.txt
diff --git a/app/app.go b/app/app.go
index dbee296..1a621df 100644
--- a/app/app.go
+++ b/app/app.go
@@ -15,6 +15,7 @@ import (
 	"github.com/canonical/go-dqlite/client"
 	"github.com/canonical/go-dqlite/driver"
 	"github.com/canonical/go-dqlite/internal/protocol"
+	"github.com/canonical/go-dqlite/logging"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/semaphore"
 )
@@ -32,11 +33,11 @@ type App struct {
 	nodeBindAddress string
 	listener        net.Listener
 	tls             *tlsSetup
-	dialFunc        client.DialFunc
-	store           client.NodeStore
+	dialFunc        protocol.DialFunc
+	store           protocol.NodeStore
 	driver          *driver.Driver
 	driverName      string
-	log             client.LogFunc
+	log             logging.Func
 	ctx             context.Context
 	stop            context.CancelFunc // Signal App.run() to stop.
 	proxyCh         chan struct{}      // Waits for App.proxy() to return.
@@ -78,7 +79,7 @@ func New(dir string, options ...Option) (app *App, err error) {
 	}()
 
 	// Load our ID, or generate one if we are joining.
-	info := client.NodeInfo{}
+	info := protocol.NodeInfo{}
 	infoFileExists, err := fileExists(dir, infoFile)
 	if err != nil {
 		return nil, err
@@ -142,15 +143,15 @@ func New(dir string, options ...Option) (app *App, err error) {
 		// If this is a brand new application node, populate the store
 		// either with the node's address (for bootstrap nodes) or with
 		// the given cluster addresses (for joining nodes).
-		nodes := []client.NodeInfo{}
+		nodes := []protocol.NodeInfo{}
 		if info.ID == dqlite.BootstrapID {
-			nodes = append(nodes, client.NodeInfo{Address: info.Address})
+			nodes = append(nodes, protocol.NodeInfo{Address: info.Address})
 		} else {
 			if len(o.Cluster) == 0 {
 				return nil, fmt.Errorf("no cluster addresses provided")
 			}
 			for _, address := range o.Cluster {
-				nodes = append(nodes, client.NodeInfo{Address: address})
+				nodes = append(nodes, protocol.NodeInfo{Address: address})
 			}
 		}
 		if err := store.Set(context.Background(), nodes); err != nil {
@@ -161,7 +162,7 @@ func New(dir string, options ...Option) (app *App, err error) {
 
 	// Start the local dqlite engine.
 	ctx, stop := context.WithCancel(context.Background())
-	var nodeDial client.DialFunc
+	var nodeDial protocol.DialFunc
 	if o.Conn != nil {
 		nodeDial = extDialFuncWithProxy(ctx, o.Conn.dialFunc)
 	} else if o.TLS != nil {
@@ -514,7 +515,7 @@ func (a *App) run(ctx context.Context, frequency time.Duration, join bool) {
 
 			// Attempt to join the cluster if this is a brand new node.
 			if join {
-				info := client.NodeInfo{ID: a.id, Address: a.address, Role: client.Spare}
+				info := protocol.NodeInfo{ID: a.id, Address: a.address, Role: client.Spare}
 				if err := cli.Add(ctx, info); err != nil {
 					a.warn("join cluster: %v", err)
 					delay = time.Second
@@ -568,7 +569,7 @@ func (a *App) run(ctx context.Context, frequency time.Duration, join bool) {
 }
 
 // Possibly change our own role at startup.
-func (a *App) maybePromoteOurselves(ctx context.Context, cli *client.Client, nodes []client.NodeInfo) error {
+func (a *App) maybePromoteOurselves(ctx context.Context, cli *client.Client, nodes []protocol.NodeInfo) error {
 	roles := a.makeRolesChanges(nodes)
 
 	role := roles.Assume(a.id)
@@ -641,8 +642,8 @@ again:
 
 // Probe all given nodes for connectivity and metadata, then return a
 // RolesChanges object.
-func (a *App) makeRolesChanges(nodes []client.NodeInfo) RolesChanges {
-	state := map[client.NodeInfo]*client.NodeMetadata{}
+func (a *App) makeRolesChanges(nodes []protocol.NodeInfo) RolesChanges {
+	state := map[protocol.NodeInfo]*client.NodeMetadata{}
 	for _, node := range nodes {
 		state[node] = nil
 	}
diff --git a/app/dial.go b/app/dial.go
index 96d536f..0375fda 100644
--- a/app/dial.go
+++ b/app/dial.go
@@ -6,12 +6,12 @@ import (
 	"fmt"
 	"net"
 
-	"github.com/canonical/go-dqlite/client"
+	"github.com/canonical/go-dqlite/internal/protocol"
 )
 
 // Like client.DialFuncWithTLS but also starts the proxy, since the raft
 // connect function only supports Unix and TCP connections.
-func makeNodeDialFunc(appCtx context.Context, config *tls.Config) client.DialFunc {
+func makeNodeDialFunc(appCtx context.Context, config *tls.Config) protocol.DialFunc {
 	dial := func(ctx context.Context, addr string) (net.Conn, error) {
 		clonedConfig := config.Clone()
 		if len(clonedConfig.ServerName) == 0 {
@@ -42,7 +42,7 @@ func makeNodeDialFunc(appCtx context.Context, config *tls.Config) client.DialFun
 
 // extDialFuncWithProxy executes given DialFunc and then copies the data back
 // and forth between the remote connection and a local unix socket.
-func extDialFuncWithProxy(appCtx context.Context, dialFunc client.DialFunc) client.DialFunc {
+func extDialFuncWithProxy(appCtx context.Context, dialFunc protocol.DialFunc) protocol.DialFunc {
 	return func(ctx context.Context, addr string) (net.Conn, error) {
 		goUnix, cUnix, err := socketpair()
 		if err != nil {
diff --git a/app/options.go b/app/options.go
index d0b0520..1e795ff 100644
--- a/app/options.go
+++ b/app/options.go
@@ -8,8 +8,10 @@ import (
 	"strings"
 	"time"
 
-	"github.com/canonical/go-dqlite"
 	"github.com/canonical/go-dqlite/client"
+	"github.com/canonical/go-dqlite/internal/bindings"
+	"github.com/canonical/go-dqlite/internal/protocol"
+	"github.com/canonical/go-dqlite/logging"
 )
 
 // Option can be used to tweak app parameters.
@@ -49,7 +51,7 @@ func WithCluster(cluster []string) Option {
 // whenever dqlite needs to make an outside connection.
 //
 // Also takes a net.Conn channel that should be received when the external connection has been accepted.
-func WithExternalConn(dialFunc client.DialFunc, acceptCh chan net.Conn) Option {
+func WithExternalConn(dialFunc protocol.DialFunc, acceptCh chan net.Conn) Option {
 	return func(options *options) {
 		options.Conn = &connSetup{
 			dialFunc: dialFunc,
@@ -140,7 +142,7 @@ func WithRolesAdjustmentFrequency(frequency time.Duration) Option {
 }
 
 // WithLogFunc sets a custom log function.
-func WithLogFunc(log client.LogFunc) Option {
+func WithLogFunc(log logging.Func) Option {
 	return func(options *options) {
 		options.Log = log
 	}
@@ -164,7 +166,7 @@ func WithNetworkLatency(latency time.Duration) Option {
 }
 
 // WithSnapshotParams sets the raft snapshot parameters.
-func WithSnapshotParams(params dqlite.SnapshotParams) Option {
+func WithSnapshotParams(params bindings.SnapshotParams) Option {
 	return func(options *options) {
 		options.SnapshotParams = params
 	}
@@ -187,14 +189,14 @@ type tlsSetup struct {
 }
 
 type connSetup struct {
-	dialFunc client.DialFunc
+	dialFunc protocol.DialFunc
 	acceptCh chan net.Conn
 }
 
 type options struct {
 	Address                  string
 	Cluster                  []string
-	Log                      client.LogFunc
+	Log                      logging.Func
 	TLS                      *tlsSetup
 	Conn                     *connSetup
 	Voters                   int
@@ -203,7 +205,7 @@ type options struct {
 	FailureDomain            uint64
 	NetworkLatency           time.Duration
 	UnixSocket               string
-	SnapshotParams           dqlite.SnapshotParams
+	SnapshotParams           bindings.SnapshotParams
 	DiskMode                 bool
 }
 
@@ -272,7 +274,7 @@ func defaultAddress() (addr string, err error) {
 	return "", fmt.Errorf("no suitable net.Interface found: %v", err)
 }
 
-func defaultLogFunc(l client.LogLevel, format string, a ...interface{}) {
+func defaultLogFunc(l logging.Level, format string, a ...interface{}) {
 	// Log only error messages
 	if l != client.LogError {
 		return
diff --git a/app/roles.go b/app/roles.go
index 5b24bdf..1fd8ba6 100644
--- a/app/roles.go
+++ b/app/roles.go
@@ -4,6 +4,7 @@ import (
 	"sort"
 
 	"github.com/canonical/go-dqlite/client"
+	"github.com/canonical/go-dqlite/internal/protocol"
 )
 
 const minVoters = 3
@@ -29,7 +30,7 @@ type RolesChanges struct {
 	// present as a key in the map, and its value should be its associated
 	// failure domain and weight metadata or nil if the node is currently
 	// offline.
-	State map[client.NodeInfo]*client.NodeMetadata
+	State map[protocol.NodeInfo]*client.NodeMetadata
 }
 
 // Assume decides if a node should assume a different role than the one it
@@ -38,7 +39,7 @@ type RolesChanges struct {
 // role in case there's a shortage of them.
 //
 // Return -1 in case no role change is needed.
-func (c *RolesChanges) Assume(id uint64) client.NodeRole {
+func (c *RolesChanges) Assume(id uint64) protocol.NodeRole {
 	// If the cluster is still too small, do nothing.
 	if c.size() < minVoters {
 		return -1
@@ -79,7 +80,7 @@ func (c *RolesChanges) Assume(id uint64) client.NodeRole {
 //
 // Return the role that should be handed over and list of candidates that
 // should receive it, in order of preference.
-func (c *RolesChanges) Handover(id uint64) (client.NodeRole, []client.NodeInfo) {
+func (c *RolesChanges) Handover(id uint64) (protocol.NodeRole, []protocol.NodeInfo) {
 	node := c.get(id)
 
 	// If we are not in the cluster, it means we were removed, just do nothing.
@@ -126,7 +127,7 @@ func (c *RolesChanges) Handover(id uint64) (client.NodeRole, []client.NodeInfo)
 //
 // Return the role that should be assigned and a list of candidates that should
 // assume it, in order of preference.
-func (c *RolesChanges) Adjust(leader uint64) (client.NodeRole, []client.NodeInfo) {
+func (c *RolesChanges) Adjust(leader uint64) (protocol.NodeRole, []protocol.NodeInfo) {
 	if c.size() == 1 {
 		return -1, nil
 	}
@@ -137,7 +138,7 @@ func (c *RolesChanges) Adjust(leader uint64) (client.NodeRole, []client.NodeInfo
 			if node.ID == leader || node.Role != client.Voter {
 				continue
 			}
-			return client.Spare, []client.NodeInfo{node}
+			return client.Spare, []protocol.NodeInfo{node}
 		}
 		return -1, nil
 	}
@@ -172,7 +173,7 @@ func (c *RolesChanges) Adjust(leader uint64) (client.NodeRole, []client.NodeInfo
 	// If we have more online voters than desired, let's demote one of
 	// them.
 	if n := len(onlineVoters); n > c.Config.Voters {
-		nodes := []client.NodeInfo{}
+		nodes := []protocol.NodeInfo{}
 		for _, node := range onlineVoters {
 			// Don't demote the leader.
 			if node.ID == leader {
@@ -207,7 +208,7 @@ func (c *RolesChanges) Adjust(leader uint64) (client.NodeRole, []client.NodeInfo
 	// If we have more online stand-bys than desired, let's demote one of
 	// them.
 	if n := len(onlineStandbys); n > c.Config.StandBys {
-		nodes := []client.NodeInfo{}
+		nodes := []protocol.NodeInfo{}
 		for _, node := range onlineStandbys {
 			// Don't demote the leader.
 			if node.ID == leader {
@@ -234,7 +235,7 @@ func (c *RolesChanges) size() int {
 
 // Return information about the node with the given ID, or nil if no node
 // matches.
-func (c *RolesChanges) get(id uint64) *client.NodeInfo {
+func (c *RolesChanges) get(id uint64) *protocol.NodeInfo {
 	for node := range c.State {
 		if node.ID == id {
 			return &node
@@ -244,8 +245,8 @@ func (c *RolesChanges) get(id uint64) *client.NodeInfo {
 }
 
 // Return the online or offline nodes with the given role.
-func (c *RolesChanges) list(role client.NodeRole, online bool) []client.NodeInfo {
-	nodes := []client.NodeInfo{}
+func (c *RolesChanges) list(role protocol.NodeRole, online bool) []protocol.NodeInfo {
+	nodes := []protocol.NodeInfo{}
 	for node, metadata := range c.State {
 		if node.Role == role && metadata != nil == online {
 			nodes = append(nodes, node)
@@ -255,13 +256,13 @@ func (c *RolesChanges) list(role client.NodeRole, online bool) []client.NodeInfo
 }
 
 // Return the number of online or offline nodes with the given role.
-func (c *RolesChanges) count(role client.NodeRole, online bool) int {
+func (c *RolesChanges) count(role protocol.NodeRole, online bool) int {
 	return len(c.list(role, online))
 }
 
 // Return a map of the failure domains associated with the
 // given nodes.
-func (c *RolesChanges) failureDomains(nodes []client.NodeInfo) map[uint64]bool {
+func (c *RolesChanges) failureDomains(nodes []protocol.NodeInfo) map[uint64]bool {
 	domains := map[uint64]bool{}
 	for _, node := range nodes {
 		metadata := c.State[node]
@@ -276,7 +277,7 @@ func (c *RolesChanges) failureDomains(nodes []client.NodeInfo) map[uint64]bool {
 // Sort the given candidates according to their failure domain and
 // weight. Candidates belonging to a failure domain different from the given
 // domains take precedence.
-func (c *RolesChanges) sortCandidates(candidates []client.NodeInfo, domains map[uint64]bool) {
+func (c *RolesChanges) sortCandidates(candidates []protocol.NodeInfo, domains map[uint64]bool) {
 	less := func(i, j int) bool {
 		metadata1 := c.metadata(candidates[i])
 		metadata2 := c.metadata(candidates[j])
@@ -300,6 +301,6 @@ func (c *RolesChanges) sortCandidates(candidates []client.NodeInfo, domains map[
 }
 
 // Return the metadata of the given node, if any.
-func (c *RolesChanges) metadata(node client.NodeInfo) *client.NodeMetadata {
+func (c *RolesChanges) metadata(node protocol.NodeInfo) *client.NodeMetadata {
 	return c.State[node]
 }
diff --git a/client/client.go b/client/client.go
index c8809be..9f6ed68 100644
--- a/client/client.go
+++ b/client/client.go
@@ -4,11 +4,12 @@ import (
 	"context"
 
 	"github.com/canonical/go-dqlite/internal/protocol"
+	"github.com/canonical/go-dqlite/logging"
 	"github.com/pkg/errors"
 )
 
 // DialFunc is a function that can be used to establish a network connection.
-type DialFunc = protocol.DialFunc
+//type DialFunc = protocol.DialFunc
 
 // Client speaks the dqlite wire protocol.
 type Client struct {
@@ -19,13 +20,13 @@ type Client struct {
 type Option func(*options)
 
 type options struct {
-	DialFunc DialFunc
-	LogFunc  LogFunc
+	DialFunc protocol.DialFunc
+	LogFunc  logging.Func
 }
 
 // WithDialFunc sets a custom dial function for creating the client network
 // connection.
-func WithDialFunc(dial DialFunc) Option {
+func WithDialFunc(dial protocol.DialFunc) Option {
 	return func(options *options) {
 		options.DialFunc = dial
 	}
@@ -33,7 +34,7 @@ func WithDialFunc(dial DialFunc) Option {
 
 // WithLogFunc sets a custom log function.
 // connection.
-func WithLogFunc(log LogFunc) Option {
+func WithLogFunc(log logging.Func) Option {
 	return func(options *options) {
 		options.LogFunc = log
 	}
@@ -65,7 +66,7 @@ func New(ctx context.Context, address string, options ...Option) (*Client, error
 }
 
 // Leader returns information about the current leader, if any.
-func (c *Client) Leader(ctx context.Context) (*NodeInfo, error) {
+func (c *Client) Leader(ctx context.Context) (*protocol.NodeInfo, error) {
 	request := protocol.Message{}
 	request.Init(16)
 	response := protocol.Message{}
@@ -82,13 +83,13 @@ func (c *Client) Leader(ctx context.Context) (*NodeInfo, error) {
 		return nil, errors.Wrap(err, "failed to parse Node response")
 	}
 
-	info := &NodeInfo{ID: id, Address: address}
+	info := &protocol.NodeInfo{ID: id, Address: address}
 
 	return info, nil
 }
 
 // Cluster returns information about all nodes in the cluster.
-func (c *Client) Cluster(ctx context.Context) ([]NodeInfo, error) {
+func (c *Client) Cluster(ctx context.Context) ([]protocol.NodeInfo, error) {
 	request := protocol.Message{}
 	request.Init(16)
 	response := protocol.Message{}
@@ -154,7 +155,7 @@ func (c *Client) Dump(ctx context.Context, dbname string) ([]File, error) {
 // The new node will have the role specified in node.Role. Note that if the
 // desired role is Voter, the node being added must be online, since it will be
 // granted voting rights only once it catches up with the leader's log.
-func (c *Client) Add(ctx context.Context, node NodeInfo) error {
+func (c *Client) Add(ctx context.Context, node protocol.NodeInfo) error {
 	request := protocol.Message{}
 	response := protocol.Message{}
 
@@ -190,7 +191,7 @@ func (c *Client) Add(ctx context.Context, node NodeInfo) error {
 //
 // If the target node does not exist or has already the desired role, an error
 // is returned.
-func (c *Client) Assign(ctx context.Context, id uint64, role NodeRole) error {
+func (c *Client) Assign(ctx context.Context, id uint64, role protocol.NodeRole) error {
 	request := protocol.Message{}
 	response := protocol.Message{}
 
diff --git a/client/dial.go b/client/dial.go
index 5466679..88cbbe1 100644
--- a/client/dial.go
+++ b/client/dial.go
@@ -18,7 +18,7 @@ func DefaultDialFunc(ctx context.Context, address string) (net.Conn, error) {
 //
 // The given dial function will be used to establish the network connection,
 // and the given TLS config will be used for encryption.
-func DialFuncWithTLS(dial DialFunc, config *tls.Config) DialFunc {
+func DialFuncWithTLS(dial protocol.DialFunc, config *tls.Config) protocol.DialFunc {
 	return func(ctx context.Context, addr string) (net.Conn, error) {
 		clonedConfig := config.Clone()
 		if len(clonedConfig.ServerName) == 0 {
diff --git a/client/leader.go b/client/leader.go
index 5de72ce..2b90946 100644
--- a/client/leader.go
+++ b/client/leader.go
@@ -12,7 +12,7 @@ import (
 // each of them check if it's the current leader. If no leader is found, the
 // function will keep retrying (with a capped exponential backoff) until the
 // given context is canceled.
-func FindLeader(ctx context.Context, store NodeStore, options ...Option) (*Client, error) {
+func FindLeader(ctx context.Context, store protocol.NodeStore, options ...Option) (*Client, error) {
 	o := defaultOptions()
 
 	for _, option := range options {
diff --git a/client/log.go b/client/log.go
index 0c4e467..ea795b0 100644
--- a/client/log.go
+++ b/client/log.go
@@ -5,10 +5,10 @@ import (
 )
 
 // LogFunc is a function that can be used for logging.
-type LogFunc = logging.Func
+//type LogFunc = logging.Func
 
 // LogLevel defines the logging level.
-type LogLevel = logging.Level
+//type LogLevel = logging.Level
 
 // Available logging levels.
 const (
@@ -20,4 +20,4 @@ const (
 )
 
 // DefaultLogFunc doesn't emit any message.
-func DefaultLogFunc(l LogLevel, format string, a ...interface{}) {}
+func DefaultLogFunc(l logging.Level, format string, a ...interface{}) {}
diff --git a/client/store.go b/client/store.go
index 79c9693..13126ef 100644
--- a/client/store.go
+++ b/client/store.go
@@ -19,16 +19,16 @@ import (
 
 // NodeStore is used by a dqlite client to get an initial list of candidate
 // dqlite nodes that it can dial in order to find a leader dqlite node to use.
-type NodeStore = protocol.NodeStore
+//type NodeStore = protocol.NodeStore
 
 // NodeRole identifies the role of a node.
-type NodeRole = protocol.NodeRole
+//type NodeRole = protocol.NodeRole
 
 // NodeInfo holds information about a single server.
-type NodeInfo = protocol.NodeInfo
+//type NodeInfo = protocol.NodeInfo
 
 // InmemNodeStore keeps the list of target dqlite nodes in memory.
-type InmemNodeStore = protocol.InmemNodeStore
+//type InmemNodeStore = protocol.InmemNodeStore
 
 // NewInmemNodeStore creates NodeStore which stores its data in-memory.
 var NewInmemNodeStore = protocol.NewInmemNodeStore
@@ -49,7 +49,7 @@ type DatabaseNodeStore struct {
 // for the schema, table and column parameters.
 //
 // It also creates the table if it doesn't exist yet.
-func DefaultNodeStore(filename string) (NodeStore, error) {
+func DefaultNodeStore(filename string) (protocol.NodeStore, error) {
 	if strings.HasSuffix(filename, ".yaml") {
 		return NewYamlNodeStore(filename)
 	}
@@ -108,7 +108,7 @@ func NewNodeStore(db *sql.DB, schema, table, column string, options ...NodeStore
 }
 
 // Get the current servers.
-func (d *DatabaseNodeStore) Get(ctx context.Context) ([]NodeInfo, error) {
+func (d *DatabaseNodeStore) Get(ctx context.Context) ([]protocol.NodeInfo, error) {
 	tx, err := d.db.Begin()
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to begin transaction")
@@ -125,14 +125,14 @@ func (d *DatabaseNodeStore) Get(ctx context.Context) ([]NodeInfo, error) {
 	}
 	defer rows.Close()
 
-	servers := make([]NodeInfo, 0)
+	servers := make([]protocol.NodeInfo, 0)
 	for rows.Next() {
 		var address string
 		err := rows.Scan(&address)
 		if err != nil {
 			return nil, errors.Wrap(err, "failed to fetch server address")
 		}
-		servers = append(servers, NodeInfo{ID: 1, Address: address})
+		servers = append(servers, protocol.NodeInfo{ID: 1, Address: address})
 	}
 	if err := rows.Err(); err != nil {
 		return nil, errors.Wrap(err, "result set failure")
@@ -142,7 +142,7 @@ func (d *DatabaseNodeStore) Get(ctx context.Context) ([]NodeInfo, error) {
 }
 
 // Set the servers addresses.
-func (d *DatabaseNodeStore) Set(ctx context.Context, servers []NodeInfo) error {
+func (d *DatabaseNodeStore) Set(ctx context.Context, servers []protocol.NodeInfo) error {
 	tx, err := d.db.Begin()
 	if err != nil {
 		return errors.Wrap(err, "failed to begin transaction")
@@ -179,13 +179,13 @@ func (d *DatabaseNodeStore) Set(ctx context.Context, servers []NodeInfo) error {
 // Persists a list addresses of dqlite nodes in a YAML file.
 type YamlNodeStore struct {
 	path    string
-	servers []NodeInfo
+	servers []protocol.NodeInfo
 	mu      sync.RWMutex
 }
 
 // NewYamlNodeStore creates a new YamlNodeStore backed by the given YAML file.
 func NewYamlNodeStore(path string) (*YamlNodeStore, error) {
-	servers := []NodeInfo{}
+	servers := []protocol.NodeInfo{}
 
 	_, err := os.Stat(path)
 	if err != nil {
@@ -212,7 +212,7 @@ func NewYamlNodeStore(path string) (*YamlNodeStore, error) {
 }
 
 // Get the current servers.
-func (s *YamlNodeStore) Get(ctx context.Context) ([]NodeInfo, error) {
+func (s *YamlNodeStore) Get(ctx context.Context) ([]protocol.NodeInfo, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()
 
@@ -220,7 +220,7 @@ func (s *YamlNodeStore) Get(ctx context.Context) ([]NodeInfo, error) {
 }
 
 // Set the servers addresses.
-func (s *YamlNodeStore) Set(ctx context.Context, servers []NodeInfo) error {
+func (s *YamlNodeStore) Set(ctx context.Context, servers []protocol.NodeInfo) error {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 
diff --git a/cmd/dqlite-demo/dqlite-demo.go b/cmd/dqlite-demo/dqlite-demo.go
index 6748b37..4c84371 100644
--- a/cmd/dqlite-demo/dqlite-demo.go
+++ b/cmd/dqlite-demo/dqlite-demo.go
@@ -13,7 +13,7 @@ import (
 	"strings"
 
 	"github.com/canonical/go-dqlite/app"
-	"github.com/canonical/go-dqlite/client"
+	"github.com/canonical/go-dqlite/logging"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	"golang.org/x/sys/unix"
@@ -38,7 +38,7 @@ Complete documentation is available at https://github.com/canonical/go-dqlite`,
 			if err := os.MkdirAll(dir, 0755); err != nil {
 				return errors.Wrapf(err, "can't create %s", dir)
 			}
-			logFunc := func(l client.LogLevel, format string, a ...interface{}) {
+			logFunc := func(l logging.Level, format string, a ...interface{}) {
 				if !verbose {
 					return
 				}
diff --git a/driver/driver.go b/driver/driver.go
index 4ac8826..841d7dd 100644
--- a/driver/driver.go
+++ b/driver/driver.go
@@ -28,21 +28,22 @@ import (
 
 	"github.com/canonical/go-dqlite/client"
 	"github.com/canonical/go-dqlite/internal/protocol"
+	"github.com/canonical/go-dqlite/logging"
 )
 
 // Driver perform queries against a dqlite server.
 type Driver struct {
-	log               client.LogFunc   // Log function to use
-	store             client.NodeStore // Holds addresses of dqlite servers
-	context           context.Context  // Global cancellation context
-	connectionTimeout time.Duration    // Max time to wait for a new connection
-	contextTimeout    time.Duration    // Default client context timeout.
-	clientConfig      protocol.Config  // Configuration for dqlite client instances
-	tracing           client.LogLevel  // Whether to trace statements
+	log               logging.Func       // Log function to use
+	store             protocol.NodeStore // Holds addresses of dqlite servers
+	context           context.Context    // Global cancellation context
+	connectionTimeout time.Duration      // Max time to wait for a new connection
+	contextTimeout    time.Duration      // Default client context timeout.
+	clientConfig      protocol.Config    // Configuration for dqlite client instances
+	tracing           logging.Level      // Whether to trace statements
 }
 
 // Error is returned in case of database errors.
-type Error = protocol.Error
+//type Error = protocol.Error
 
 // Error codes. Values here mostly overlap with native SQLite codes.
 const (
@@ -66,17 +67,17 @@ const MaxTupleParams = 255
 // Option can be used to tweak driver parameters.
 type Option func(*options)
 
-// NodeStore is a convenience alias of client.NodeStore.
-type NodeStore = client.NodeStore
+// NodeStore is a convenience alias of protocol.NodeStore.
+//type NodeStore = protocol.NodeStore
 
 // NodeInfo is a convenience alias of client.NodeInfo.
-type NodeInfo = client.NodeInfo
+//type NodeInfo = client.NodeInfo
 
 // DefaultNodeStore is a convenience alias of client.DefaultNodeStore.
 var DefaultNodeStore = client.DefaultNodeStore
 
 // WithLogFunc sets a custom logging function.
-func WithLogFunc(log client.LogFunc) Option {
+func WithLogFunc(log logging.Func) Option {
 	return func(options *options) {
 		options.Log = log
 	}
@@ -84,10 +85,10 @@ func WithLogFunc(log client.LogFunc) Option {
 
 // DialFunc is a function that can be used to establish a network connection
 // with a dqlite node.
-type DialFunc = protocol.DialFunc
+//type DialFunc = protocol.DialFunc
 
 // WithDialFunc sets a custom dial function.
-func WithDialFunc(dial DialFunc) Option {
+func WithDialFunc(dial protocol.DialFunc) Option {
 	return func(options *options) {
 		options.Dial = protocol.DialFunc(dial)
 	}
@@ -172,7 +173,7 @@ func WithContextTimeout(timeout time.Duration) Option {
 
 // WithTracing will emit a log message at the given level every time a
 // statement gets executed.
-func WithTracing(level client.LogLevel) Option {
+func WithTracing(level logging.Level) Option {
 	return func(options *options) {
 		options.Tracing = level
 	}
@@ -180,7 +181,7 @@ func WithTracing(level client.LogLevel) Option {
 
 // NewDriver creates a new dqlite driver, which also implements the
 // driver.Driver interface.
-func New(store client.NodeStore, options ...Option) (*Driver, error) {
+func New(store protocol.NodeStore, options ...Option) (*Driver, error) {
 	o := defaultOptions()
 
 	for _, option := range options {
@@ -208,7 +209,7 @@ func New(store client.NodeStore, options ...Option) (*Driver, error) {
 
 // Hold configuration options for a dqlite driver.
 type options struct {
-	Log                     client.LogFunc
+	Log                     logging.Func
 	Dial                    protocol.DialFunc
 	AttemptTimeout          time.Duration
 	ConnectionTimeout       time.Duration
@@ -217,7 +218,7 @@ type options struct {
 	ConnectionBackoffCap    time.Duration
 	RetryLimit              uint
 	Context                 context.Context
-	Tracing                 client.LogLevel
+	Tracing                 logging.Level
 }
 
 // Create a options object with sane defaults.
@@ -328,13 +329,13 @@ var ErrNoAvailableLeader = protocol.ErrNoAvailableLeader
 
 // Conn implements the sql.Conn interface.
 type Conn struct {
-	log            client.LogFunc
+	log            logging.Func
 	protocol       *protocol.Protocol
 	request        protocol.Message
 	response       protocol.Message
 	id             uint32 // Database ID.
 	contextTimeout time.Duration
-	tracing        client.LogLevel
+	tracing        logging.Level
 }
 
 // PrepareContext returns a prepared statement, bound to this connection.
@@ -491,7 +492,7 @@ func (c *Conn) Begin() (driver.Tx, error) {
 // Tx is a transaction.
 type Tx struct {
 	conn *Conn
-	log  client.LogFunc
+	log  logging.Func
 }
 
 // Commit the transaction.
@@ -525,9 +526,9 @@ type Stmt struct {
 	db       uint32
 	id       uint32
 	params   uint64
-	log      client.LogFunc
+	log      logging.Func
 	sql      string // Prepared SQL, only set when tracing
-	tracing  client.LogLevel
+	tracing  logging.Level
 }
 
 // Close closes the statement.
@@ -643,7 +644,7 @@ type Rows struct {
 	rows     protocol.Rows
 	consumed bool
 	types    []string
-	log      client.LogFunc
+	log      logging.Func
 }
 
 // Columns returns the names of the columns. The number of
@@ -754,7 +755,7 @@ type unwrappable interface {
 	Unwrap() error
 }
 
-func driverError(log client.LogFunc, err error) error {
+func driverError(log logging.Func, err error) error {
 	switch err := errors.Cause(err).(type) {
 	case syscall.Errno:
 		log(client.LogDebug, "network connection lost: %v", err)
@@ -785,7 +786,7 @@ func driverError(log client.LogFunc, err error) error {
 				log(client.LogWarn, "unexpected error code (%d - %s)", err.Code, err.Description)
 				return driver.ErrBadConn
 			}
-			return Error{
+			return protocol.Error{
 				Code:    int(err.Code),
 				Message: err.Description,
 			}
diff --git a/node.go b/node.go
index baa5e94..205a771 100644
--- a/node.go
+++ b/node.go
@@ -6,12 +6,14 @@ import (
 
 	"github.com/canonical/go-dqlite/client"
 	"github.com/canonical/go-dqlite/internal/bindings"
+	"github.com/canonical/go-dqlite/internal/protocol"
+	"github.com/canonical/go-dqlite/logging"
 	"github.com/pkg/errors"
 )
 
 // Node runs a dqlite node.
 type Node struct {
-	log         client.LogFunc // Logger
+	log         logging.Func   // Logger
 	server      *bindings.Node // Low-level C implementation
 	acceptCh    chan error     // Receives connection handling errors
 	id          uint64
@@ -21,7 +23,7 @@ type Node struct {
 }
 
 // NodeInfo is a convenience alias for client.NodeInfo.
-type NodeInfo = client.NodeInfo
+//type NodeInfo = client.NodeInfo
 
 // SnapshotParams exposes bindings.SnapshotParams. Used for setting dqlite's
 // snapshot parameters.
@@ -29,13 +31,13 @@ type NodeInfo = client.NodeInfo
 // taken. The higher this number, the lower the frequency of the snapshots.
 // SnapshotParams.Trailing controls how many raft log entries are retained after
 // taking a snapshot.
-type SnapshotParams = bindings.SnapshotParams
+//type SnapshotParams = bindings.SnapshotParams
 
 // Option can be used to tweak node parameters.
 type Option func(*options)
 
 // WithDialFunc sets a custom dial function for the server.
-func WithDialFunc(dial client.DialFunc) Option {
+func WithDialFunc(dial protocol.DialFunc) Option {
 	return func(options *options) {
 		options.DialFunc = dial
 	}
@@ -63,7 +65,7 @@ func WithFailureDomain(code uint64) Option {
 }
 
 // WithSnapshotParams sets the snapshot parameters of the node.
-func WithSnapshotParams(params SnapshotParams) Option {
+func WithSnapshotParams(params bindings.SnapshotParams) Option {
 	return func(options *options) {
 		options.SnapshotParams = params
 	}
@@ -158,14 +160,14 @@ func (s *Node) Start() error {
 //
 // DEPRECATED: Use ReconfigureMembership instead, which does not require
 // instantiating a new Node object.
-func (s *Node) Recover(cluster []NodeInfo) error {
+func (s *Node) Recover(cluster []protocol.NodeInfo) error {
 	return s.server.Recover(cluster)
 }
 
 // Hold configuration options for a dqlite server.
 type options struct {
-	Log            client.LogFunc
-	DialFunc       client.DialFunc
+	Log            logging.Func
+	DialFunc       protocol.DialFunc
 	BindAddress    string
 	NetworkLatency uint64
 	FailureDomain  uint64
@@ -201,7 +203,7 @@ func GenerateID(address string) uint64 {
 //
 // It forces appending a new configuration to the raft log stored in the given
 // directory, effectively replacing the current configuration.
-func ReconfigureMembership(dir string, cluster []NodeInfo) error {
+func ReconfigureMembership(dir string, cluster []protocol.NodeInfo) error {
 	server, err := bindings.NewNode(context.Background(), 1, "1", dir)
 	if err != nil {
 		return err
@@ -218,7 +220,7 @@ func ReconfigureMembership(dir string, cluster []NodeInfo) error {
 // In comparision with ReconfigureMembership, this function takes the node role
 // into account and makes use of a dqlite API that supports extending the
 // NodeInfo struct.
-func ReconfigureMembershipExt(dir string, cluster []NodeInfo) error {
+func ReconfigureMembershipExt(dir string, cluster []protocol.NodeInfo) error {
 	server, err := bindings.NewNode(context.Background(), 1, "1", dir)
 	if err != nil {
 		return err

@MathieuBordere MathieuBordere added the Bug Confirmed to be a bug label Jun 12, 2023
@cole-miller
Copy link
Contributor

Closing since the goc toolchain is our primary target and it's not clear what our support policy should be for gccgo; as mentioned above, we're happy to take patches to get gccgo builds working, but it's not a priority for us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Confirmed to be a bug
Projects
None yet
Development

No branches or pull requests

4 participants