github.com/hyperledger-gerrit-archive/fabric-ca@v2.0.0-alpha.0.20190916143245-4cd4192f0366+incompatible/lib/server/db/db.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package db
     8  
     9  import (
    10  	"context"
    11  	"database/sql"
    12  	"time"
    13  
    14  	"github.com/cloudflare/cfssl/certdb"
    15  	"github.com/hyperledger/fabric-ca/lib/server/db/util"
    16  	"github.com/jmoiron/sqlx"
    17  )
    18  
    19  //go:generate counterfeiter -o mocks/fabricCaDb.go -fake-name FabricCADB . FabricCADB
    20  //go:generate mockery -name FabricCADB -output ../idemix/mocks -case underscore
    21  
    22  // FabricCADB is the interface that wrapper off SqlxDB
    23  type FabricCADB interface {
    24  	IsInitialized() bool
    25  	SetDBInitialized(bool)
    26  	// BeginTx has same behavior as MustBegin except it returns FabricCATx
    27  	// instead of *sqlx.Tx
    28  	BeginTx() FabricCATx
    29  	DriverName() string
    30  
    31  	Select(funcName string, dest interface{}, query string, args ...interface{}) error
    32  	Exec(funcName, query string, args ...interface{}) (sql.Result, error)
    33  	NamedExec(funcName, query string, arg interface{}) (sql.Result, error)
    34  	Get(funcName string, dest interface{}, query string, args ...interface{}) error
    35  	Queryx(funcName, query string, args ...interface{}) (*sqlx.Rows, error)
    36  	Rebind(query string) string
    37  	MustBegin() *sqlx.Tx
    38  	Close() error
    39  	SetMaxOpenConns(n int)
    40  	PingContext(ctx context.Context) error
    41  }
    42  
    43  //go:generate counterfeiter -o mocks/sqlxDB.go -fake-name SqlxDB . SqlxDB
    44  
    45  // SqlxDB is the interface with functions implemented by sqlx.DB
    46  // object that are used by Fabric CA server
    47  type SqlxDB interface {
    48  	DriverName() string
    49  	Select(dest interface{}, query string, args ...interface{}) error
    50  	Exec(query string, args ...interface{}) (sql.Result, error)
    51  	NamedExec(query string, arg interface{}) (sql.Result, error)
    52  	Get(dest interface{}, query string, args ...interface{}) error
    53  	Queryx(query string, args ...interface{}) (*sqlx.Rows, error)
    54  	Rebind(query string) string
    55  	MustBegin() *sqlx.Tx
    56  	Close() error
    57  	SetMaxOpenConns(n int)
    58  	PingContext(ctx context.Context) error
    59  }
    60  
    61  // CertRecord extends CFSSL CertificateRecord by adding an enrollment ID to the record
    62  type CertRecord struct {
    63  	ID    string `db:"id"`
    64  	Level int    `db:"level"`
    65  	certdb.CertificateRecord
    66  }
    67  
    68  // AffiliationRecord defines the properties of an affiliation
    69  type AffiliationRecord struct {
    70  	ID     int    `db:"id"`
    71  	Name   string `db:"name"`
    72  	Prekey string `db:"prekey"`
    73  	Level  int    `db:"level"`
    74  }
    75  
    76  // DB is an adapter for sqlx.DB and implements FabricCADB interface
    77  type DB struct {
    78  	DB SqlxDB
    79  	// Indicates if database was successfully initialized
    80  	IsDBInitialized bool
    81  	CAName          string
    82  	Metrics         *Metrics
    83  }
    84  
    85  // New creates an instance of DB
    86  func New(db SqlxDB, caName string, metrics *Metrics) *DB {
    87  	return &DB{
    88  		DB:      db,
    89  		CAName:  caName,
    90  		Metrics: metrics,
    91  	}
    92  }
    93  
    94  // IsInitialized returns true if db is intialized, else false
    95  func (db *DB) IsInitialized() bool {
    96  	return db.IsDBInitialized
    97  }
    98  
    99  // SetDBInitialized sets the value for Isdbinitialized
   100  func (db *DB) SetDBInitialized(b bool) {
   101  	db.IsDBInitialized = b
   102  }
   103  
   104  // BeginTx implements BeginTx method of FabricCADB interface
   105  func (db *DB) BeginTx() FabricCATx {
   106  	return &TX{
   107  		TX:     db.DB.MustBegin(),
   108  		Record: db,
   109  	}
   110  }
   111  
   112  // Select performs select sql statement
   113  func (db *DB) Select(funcName string, dest interface{}, query string, args ...interface{}) error {
   114  	startTime := time.Now()
   115  	err := db.DB.Select(dest, query, args...)
   116  	db.recordMetric(startTime, funcName, "Select")
   117  	return err
   118  }
   119  
   120  // Exec executes query
   121  func (db *DB) Exec(funcName, query string, args ...interface{}) (sql.Result, error) {
   122  	startTime := time.Now()
   123  	res, err := db.DB.Exec(query, args...)
   124  	db.recordMetric(startTime, funcName, "Exec")
   125  	return res, err
   126  }
   127  
   128  // NamedExec executes query
   129  func (db *DB) NamedExec(funcName, query string, args interface{}) (sql.Result, error) {
   130  	startTime := time.Now()
   131  	res, err := db.DB.NamedExec(query, args)
   132  	db.recordMetric(startTime, funcName, "NamedExec")
   133  	return res, err
   134  }
   135  
   136  // Get executes query
   137  func (db *DB) Get(funcName string, dest interface{}, query string, args ...interface{}) error {
   138  	startTime := time.Now()
   139  	err := db.DB.Get(dest, query, args...)
   140  	db.recordMetric(startTime, funcName, "Get")
   141  	return err
   142  }
   143  
   144  // Queryx executes query
   145  func (db *DB) Queryx(funcName, query string, args ...interface{}) (*sqlx.Rows, error) {
   146  	startTime := time.Now()
   147  	rows, err := db.DB.Queryx(query, args...)
   148  	db.recordMetric(startTime, funcName, "Queryx")
   149  	return rows, err
   150  }
   151  
   152  // MustBegin starts a transaction
   153  func (db *DB) MustBegin() *sqlx.Tx {
   154  	return db.DB.MustBegin()
   155  }
   156  
   157  // DriverName returns database driver name
   158  func (db *DB) DriverName() string {
   159  	return db.DB.DriverName()
   160  }
   161  
   162  // Rebind parses query to properly format query
   163  func (db *DB) Rebind(query string) string {
   164  	return db.DB.Rebind(query)
   165  }
   166  
   167  // Close closes db
   168  func (db *DB) Close() error {
   169  	return db.DB.Close()
   170  }
   171  
   172  // SetMaxOpenConns sets number of max open connections
   173  func (db *DB) SetMaxOpenConns(n int) {
   174  	db.DB.SetMaxOpenConns(n)
   175  }
   176  
   177  // PingContext pings the database
   178  func (db *DB) PingContext(ctx context.Context) error {
   179  	return db.DB.PingContext(ctx)
   180  }
   181  
   182  func (db *DB) recordMetric(startTime time.Time, funcName, dbapiName string) {
   183  	if db.Metrics == nil {
   184  		return
   185  	}
   186  	db.Metrics.APICounter.With("ca_name", db.CAName, "func_name", funcName, "dbapi_name", dbapiName).Add(1)
   187  	db.Metrics.APIDuration.With("ca_name", db.CAName, "func_name", funcName, "dbapi_name", dbapiName).Observe(time.Since(startTime).Seconds())
   188  }
   189  
   190  // CurrentDBLevels returns current levels from the database
   191  func CurrentDBLevels(db FabricCADB) (*util.Levels, error) {
   192  	var err error
   193  	var identityLevel, affiliationLevel, certificateLevel, credentialLevel, rcinfoLevel, nonceLevel int
   194  
   195  	err = getProperty(db, "identity.level", &identityLevel)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	err = getProperty(db, "affiliation.level", &affiliationLevel)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	err = getProperty(db, "certificate.level", &certificateLevel)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	err = getProperty(db, "credential.level", &credentialLevel)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	err = getProperty(db, "rcinfo.level", &rcinfoLevel)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	err = getProperty(db, "nonce.level", &nonceLevel)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	return &util.Levels{
   220  		Identity:    identityLevel,
   221  		Affiliation: affiliationLevel,
   222  		Certificate: certificateLevel,
   223  		Credential:  credentialLevel,
   224  		RAInfo:      rcinfoLevel,
   225  		Nonce:       nonceLevel,
   226  	}, nil
   227  }
   228  
   229  func getProperty(db FabricCADB, propName string, val *int) error {
   230  	err := db.Get("GetProperty", val, db.Rebind("Select value FROM properties WHERE (property = ?)"), propName)
   231  	if err != nil && err.Error() == "sql: no rows in result set" {
   232  		return nil
   233  	}
   234  	return err
   235  }