Repository navigation
Expand file tree
/
Copy pathdatabase.go
More file actions
119 lines (108 loc) · 3.23 KB
/
Copy pathdatabase.go
File metadata and controls
119 lines (108 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright 2026 The kine-fdb Authors
// SPDX-License-Identifier: Apache-2.0
//
// Process-wide FoundationDB client setup: API version selection, network
// options such as TLS and tracing, and a cache of database handles.
package fdbdriver
import (
"fmt"
"sync"
"github.com/apple/foundationdb/bindings/go/src/fdb"
)
// The FoundationDB client is a process-wide singleton: the API version and
// network options can be chosen once, before the network thread starts.
// Database handles are cached per cluster file and intentionally never
// closed, because the Go bindings share one handle per cluster file and
// closing it would invalidate every other user of that handle.
var client struct {
sync.Mutex
networkSet bool
network networkSettings
dbs map[string]fdb.Database
}
type networkSettings struct {
tls TLSConfig
traceDir string
traceFormat string
}
func openDatabase(cfg Config) (fdb.Database, error) {
client.Lock()
defer client.Unlock()
if err := selectAPIVersion(cfg.APIVersion); err != nil {
return fdb.Database{}, err
}
want := networkSettings{tls: cfg.TLS, traceDir: cfg.TraceDir}
if cfg.TraceDir != "" {
want.traceFormat = cfg.TraceFormat
}
if !client.networkSet {
if err := applyNetworkSettings(want); err != nil {
return fdb.Database{}, err
}
client.network = want
client.networkSet = true
} else if client.network != want {
return fdb.Database{}, fmt.Errorf("fdb: TLS and trace options must be identical for every endpoint in one process")
}
if db, ok := client.dbs[cfg.ClusterFile]; ok {
return db, nil
}
db, err := fdb.OpenDatabase(cfg.ClusterFile)
if err != nil {
return fdb.Database{}, fmt.Errorf("fdb: open database: %w", err)
}
if client.dbs == nil {
client.dbs = make(map[string]fdb.Database)
}
client.dbs[cfg.ClusterFile] = db
return db, nil
}
func selectAPIVersion(version int) error {
if fdb.IsAPIVersionSelected() {
selected := fdb.MustGetAPIVersion()
if selected != version {
return fmt.Errorf("fdb: API version %d is already selected in this process; cannot use %d", selected, version)
}
return nil
}
if err := fdb.APIVersion(version); err != nil {
return fmt.Errorf("fdb: select API version %d: %w", version, err)
}
return nil
}
func applyNetworkSettings(s networkSettings) error {
opts := fdb.Options()
set := func(name string, err error) error {
if err != nil {
return fmt.Errorf("fdb: set network option %s: %w", name, err)
}
return nil
}
steps := []struct {
name string
value string
apply func(string) error
}{
{"tls_cert_file", s.tls.CertFile, opts.SetTLSCertPath},
{"tls_key_file", s.tls.KeyFile, opts.SetTLSKeyPath},
{"tls_ca_file", s.tls.CAFile, opts.SetTLSCaPath},
{"tls_password", s.tls.Password, opts.SetTLSPassword},
{"tls_verify_peers", s.tls.VerifyPeers, func(v string) error { return opts.SetTLSVerifyPeers([]byte(v)) }},
{"trace_dir", s.traceDir, opts.SetTraceEnable},
{"trace_format", s.traceFormat, opts.SetTraceFormat},
}
for _, step := range steps {
if step.value == "" {
continue
}
if err := set(step.name, step.apply(step.value)); err != nil {
return err
}
}
if s.traceDir != "" {
if err := set("trace_log_group", opts.SetTraceLogGroup("kine-fdb")); err != nil {
return err
}
}
return nil
}