-
Notifications
You must be signed in to change notification settings - Fork 1
/
db.go
235 lines (204 loc) · 6.51 KB
/
db.go
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package db
import (
"context"
"database/sql"
"time"
"github.com/cloudflare/cfssl/certdb"
"github.com/hyperledger/fabric-ca/lib/server/db/util"
"github.com/jmoiron/sqlx"
)
//go:generate counterfeiter -o mocks/fabricCaDb.go -fake-name FabricCADB . FabricCADB
//go:generate mockery -name FabricCADB -output ../idemix/mocks -case underscore
// FabricCADB is the interface that wrapper off SqlxDB
type FabricCADB interface {
IsInitialized() bool
SetDBInitialized(bool)
// BeginTx has same behavior as MustBegin except it returns FabricCATx
// instead of *sqlx.Tx
BeginTx() FabricCATx
DriverName() string
Select(funcName string, dest interface{}, query string, args ...interface{}) error
Exec(funcName, query string, args ...interface{}) (sql.Result, error)
NamedExec(funcName, query string, arg interface{}) (sql.Result, error)
Get(funcName string, dest interface{}, query string, args ...interface{}) error
Queryx(funcName, query string, args ...interface{}) (*sqlx.Rows, error)
Rebind(query string) string
MustBegin() *sqlx.Tx
Close() error
SetMaxOpenConns(n int)
PingContext(ctx context.Context) error
}
//go:generate counterfeiter -o mocks/sqlxDB.go -fake-name SqlxDB . SqlxDB
// SqlxDB is the interface with functions implemented by sqlx.DB
// object that are used by Fabric CA server
type SqlxDB interface {
DriverName() string
Select(dest interface{}, query string, args ...interface{}) error
Exec(query string, args ...interface{}) (sql.Result, error)
NamedExec(query string, arg interface{}) (sql.Result, error)
Get(dest interface{}, query string, args ...interface{}) error
Queryx(query string, args ...interface{}) (*sqlx.Rows, error)
Rebind(query string) string
MustBegin() *sqlx.Tx
Close() error
SetMaxOpenConns(n int)
PingContext(ctx context.Context) error
}
// CertRecord extends CFSSL CertificateRecord by adding an enrollment ID to the record
type CertRecord struct {
ID string `db:"id"`
Level int `db:"level"`
certdb.CertificateRecord
}
// AffiliationRecord defines the properties of an affiliation
type AffiliationRecord struct {
ID int `db:"id"`
Name string `db:"name"`
Prekey string `db:"prekey"`
Level int `db:"level"`
}
// DB is an adapter for sqlx.DB and implements FabricCADB interface
type DB struct {
DB SqlxDB
// Indicates if database was successfully initialized
IsDBInitialized bool
CAName string
Metrics *Metrics
}
// New creates an instance of DB
func New(db SqlxDB, caName string, metrics *Metrics) *DB {
return &DB{
DB: db,
CAName: caName,
Metrics: metrics,
}
}
// IsInitialized returns true if db is intialized, else false
func (db *DB) IsInitialized() bool {
return db.IsDBInitialized
}
// SetDBInitialized sets the value for Isdbinitialized
func (db *DB) SetDBInitialized(b bool) {
db.IsDBInitialized = b
}
// BeginTx implements BeginTx method of FabricCADB interface
func (db *DB) BeginTx() FabricCATx {
return &TX{
TX: db.DB.MustBegin(),
Record: db,
}
}
// Select performs select sql statement
func (db *DB) Select(funcName string, dest interface{}, query string, args ...interface{}) error {
startTime := time.Now()
err := db.DB.Select(dest, query, args...)
db.recordMetric(startTime, funcName, "Select")
return err
}
// Exec executes query
func (db *DB) Exec(funcName, query string, args ...interface{}) (sql.Result, error) {
startTime := time.Now()
res, err := db.DB.Exec(query, args...)
db.recordMetric(startTime, funcName, "Exec")
return res, err
}
// NamedExec executes query
func (db *DB) NamedExec(funcName, query string, args interface{}) (sql.Result, error) {
startTime := time.Now()
res, err := db.DB.NamedExec(query, args)
db.recordMetric(startTime, funcName, "NamedExec")
return res, err
}
// Get executes query
func (db *DB) Get(funcName string, dest interface{}, query string, args ...interface{}) error {
startTime := time.Now()
err := db.DB.Get(dest, query, args...)
db.recordMetric(startTime, funcName, "Get")
return err
}
// Queryx executes query
func (db *DB) Queryx(funcName, query string, args ...interface{}) (*sqlx.Rows, error) {
startTime := time.Now()
rows, err := db.DB.Queryx(query, args...)
db.recordMetric(startTime, funcName, "Queryx")
return rows, err
}
// MustBegin starts a transaction
func (db *DB) MustBegin() *sqlx.Tx {
return db.DB.MustBegin()
}
// DriverName returns database driver name
func (db *DB) DriverName() string {
return db.DB.DriverName()
}
// Rebind parses query to properly format query
func (db *DB) Rebind(query string) string {
return db.DB.Rebind(query)
}
// Close closes db
func (db *DB) Close() error {
return db.DB.Close()
}
// SetMaxOpenConns sets number of max open connections
func (db *DB) SetMaxOpenConns(n int) {
db.DB.SetMaxOpenConns(n)
}
// PingContext pings the database
func (db *DB) PingContext(ctx context.Context) error {
return db.DB.PingContext(ctx)
}
func (db *DB) recordMetric(startTime time.Time, funcName, dbapiName string) {
if db.Metrics == nil {
return
}
db.Metrics.APICounter.With("ca_name", db.CAName, "func_name", funcName, "dbapi_name", dbapiName).Add(1)
db.Metrics.APIDuration.With("ca_name", db.CAName, "func_name", funcName, "dbapi_name", dbapiName).Observe(time.Since(startTime).Seconds())
}
// CurrentDBLevels returns current levels from the database
func CurrentDBLevels(db FabricCADB) (*util.Levels, error) {
var err error
var identityLevel, affiliationLevel, certificateLevel, credentialLevel, rcinfoLevel, nonceLevel int
err = getProperty(db, "identity.level", &identityLevel)
if err != nil {
return nil, err
}
err = getProperty(db, "affiliation.level", &affiliationLevel)
if err != nil {
return nil, err
}
err = getProperty(db, "certificate.level", &certificateLevel)
if err != nil {
return nil, err
}
err = getProperty(db, "credential.level", &credentialLevel)
if err != nil {
return nil, err
}
err = getProperty(db, "rcinfo.level", &rcinfoLevel)
if err != nil {
return nil, err
}
err = getProperty(db, "nonce.level", &nonceLevel)
if err != nil {
return nil, err
}
return &util.Levels{
Identity: identityLevel,
Affiliation: affiliationLevel,
Certificate: certificateLevel,
Credential: credentialLevel,
RAInfo: rcinfoLevel,
Nonce: nonceLevel,
}, nil
}
func getProperty(db FabricCADB, propName string, val *int) error {
err := db.Get("GetProperty", val, db.Rebind("Select value FROM properties WHERE (property = ?)"), propName)
if err != nil && err.Error() == "sql: no rows in result set" {
return nil
}
return err
}