由图片可以看出peer启动节点后先初始化一下日志
然后进入Server函数
//==============================================================================
//peer node start 之后做日志初始化之后就进入到server函数
//==============================================================================
func serve(args []string) error {
// Parameter overrides must be processed before any paramaters are
// cached. Failures to cache cause the server to terminate immediately.
//在其他参数被缓存起来之前参数覆盖必须处理,失败缓存导致服务立即结束
if chaincodeDevMode {
logger.Info("Running in chaincode development mode")
logger.Info("Set consensus to NOOPS and user starts chaincode")
logger.Info("Disable loading validity system chaincode")
viper.Set("peer.validator.enabled", "true")
viper.Set("peer.validator.consensus", "noops")
viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)
}
if err := peer.CacheConfiguration(); err != nil {
return err
}
peerEndpoint, err := peer.GetPeerEndpoint()
if err != nil {
err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)
return err
}
//启动grpc服务,监听7051端口
listenAddr := viper.GetString("peer.listenAddress")
if "" == listenAddr {
logger.Debug("Listen address not specified, using peer endpoint address")
listenAddr = peerEndpoint.Address
}
lis, err := net.Listen("tcp", listenAddr)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
//创建EventHub服务器,通过调用createEventHubServer方法实现,该服务也是grpc,只有VP
//才能开启
ehubLis, ehubGrpcServer, err := createEventHubServer()
if err != nil {
grpclog.Fatalf("Failed to create ehub server: %v", err)
}
logger.Infof("Security enabled status: %t", core.SecurityEnabled())
if viper.GetBool("security.privacy") {
if core.SecurityEnabled() {
logger.Infof("Privacy enabled status: true")
} else {
panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))
}
} else {
logger.Infof("Privacy enabled status: false")
}
//启动rockdb数据库
db.Start()
var opts []grpc.ServerOption
if comm.TLSEnabled() {
creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),
viper.GetString("peer.tls.key.file"))
if err != nil {
grpclog.Fatalf("Failed to generate credentials %v", err)
}
opts = []grpc.ServerOption{grpc.Creds(creds)}
}
//创建一个grpc服务
grpcServer := grpc.NewServer(opts...)
//注册Chaincode支持服务器
secHelper, err := getSecHelper()
if err != nil {
return err
}
secHelperFunc := func() crypto.Peer {
return secHelper
}
registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)
var peerServer *peer.Impl
// 创建peer服务器,主意区分VP和NVP节点
if peer.ValidatorEnabled() {
logger.Debug("Running as validating peer - making genesis block if needed")
makeGenesisError := genesis.MakeGenesis()
if makeGenesisError != nil {
return makeGenesisError
}
logger.Debugf("Running as validating peer - installing consensus %s",
viper.GetString("peer.validator.consensus"))
peerServer, err = peer.NewPeerWithEngine(secHelperFunc, helper.GetEngine)
} else {
logger.Debug("Running as non-validating peer")
peerServer, err = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)
}
if err != nil {
logger.Fatalf("Failed creating new peer with handler %v", err)
return err
}
// 注册peer服务
pb.RegisterPeerServer(grpcServer, peerServer)
// 注册管理服务器
pb.RegisterAdminServer(grpcServer, core.NewAdminServer())
// 注册Devops服务器
serverDevops := core.NewDevopsServer(peerServer)
pb.RegisterDevopsServer(grpcServer, serverDevops)
// 注册ServerOpenchain服务器
serverOpenchain, err := rest.NewOpenchainServerWithPeerInfo(peerServer)
if err != nil {
err = fmt.Errorf("Error creating OpenchainServer: %s", err)
return err
}
pb.RegisterOpenchainServer(grpcServer, serverOpenchain)
// 如果配置了的话创建和注册REST服务
if viper.GetBool("rest.enabled") {
go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)
}
logger.Infof("Starting peer with ID=%s, network ID=%s, address=%s, rootnodes=%v, validator=%v",
peerEndpoint.ID, viper.GetString("peer.networkId"), peerEndpoint.Address,
viper.GetString("peer.discovery.rootnode"), peer.ValidatorEnabled())
// 启动GRPC服务器. 如果是必须的话在一个goroutine中完成这样我们能够部署genesis
serve := make(chan error)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
serve <- nil
}()
go func() {
var grpcErr error
if grpcErr = grpcServer.Serve(lis); grpcErr != nil {
grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)
} else {
logger.Info("grpc server exited")
}
serve <- grpcErr
}()
if err := writePid(viper.GetString("peer.fileSystemPath")+"/peer.pid", os.Getpid()); err != nil {
return err
}
// 启动eventHub服务
if ehubGrpcServer != nil && ehubLis != nil {
go ehubGrpcServer.Serve(ehubLis)
}
if viper.GetBool("peer.profile.enabled") {
go func() {
profileListenAddress := viper.GetString("peer.profile.listenAddress")
logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)
if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {
logger.Errorf("Error starting profiler: %s", profileErr)
}
}()
}
// Block until grpc server exits 产生块直到grpc服务退出
return <-serve
}
所过程在代码中的注释可以看明白
由图片可以看出peer启动节点后先初始化一下日志
然后进入Server函数
//==============================================================================
//peer node start 之后做日志初始化之后就进入到server函数
//==============================================================================
func serve(args []string) error {
// Parameter overrides must be processed before any paramaters are
// cached. Failures to cache cause the server to terminate immediately.
//在其他参数被缓存起来之前参数覆盖必须处理,失败缓存导致服务立即结束
if chaincodeDevMode {
logger.Info("Running in chaincode development mode")
logger.Info("Set consensus to NOOPS and user starts chaincode")
logger.Info("Disable loading validity system chaincode")
viper.Set("peer.validator.enabled", "true")
viper.Set("peer.validator.consensus", "noops")
viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)
}
if err := peer.CacheConfiguration(); err != nil {
return err
}
peerEndpoint, err := peer.GetPeerEndpoint()
if err != nil {
err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)
return err
}
//启动grpc服务,监听7051端口
listenAddr := viper.GetString("peer.listenAddress")
if "" == listenAddr {
logger.Debug("Listen address not specified, using peer endpoint address")
listenAddr = peerEndpoint.Address
}
lis, err := net.Listen("tcp", listenAddr)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
//创建EventHub服务器,通过调用createEventHubServer方法实现,该服务也是grpc,只有VP
//才能开启
ehubLis, ehubGrpcServer, err := createEventHubServer()
if err != nil {
grpclog.Fatalf("Failed to create ehub server: %v", err)
}
logger.Infof("Security enabled status: %t", core.SecurityEnabled())
if viper.GetBool("security.privacy") {
if core.SecurityEnabled() {
logger.Infof("Privacy enabled status: true")
} else {
panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))
}
} else {
logger.Infof("Privacy enabled status: false")
}
//启动rockdb数据库
db.Start()
var opts []grpc.ServerOption
if comm.TLSEnabled() {
creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),
viper.GetString("peer.tls.key.file"))
if err != nil {
grpclog.Fatalf("Failed to generate credentials %v", err)
}
opts = []grpc.ServerOption{grpc.Creds(creds)}
}
//创建一个grpc服务
grpcServer := grpc.NewServer(opts...)
//注册Chaincode支持服务器
secHelper, err := getSecHelper()
if err != nil {
return err
}
secHelperFunc := func() crypto.Peer {
return secHelper
}
registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)
var peerServer *peer.Impl
// 创建peer服务器,主意区分VP和NVP节点
if peer.ValidatorEnabled() {
logger.Debug("Running as validating peer - making genesis block if needed")
makeGenesisError := genesis.MakeGenesis()
if makeGenesisError != nil {
return makeGenesisError
}
logger.Debugf("Running as validating peer - installing consensus %s",
viper.GetString("peer.validator.consensus"))
peerServer, err = peer.NewPeerWithEngine(secHelperFunc, helper.GetEngine)
} else {
logger.Debug("Running as non-validating peer")
peerServer, err = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)
}
if err != nil {
logger.Fatalf("Failed creating new peer with handler %v", err)
return err
}
// 注册peer服务
pb.RegisterPeerServer(grpcServer, peerServer)
// 注册管理服务器
pb.RegisterAdminServer(grpcServer, core.NewAdminServer())
// 注册Devops服务器
serverDevops := core.NewDevopsServer(peerServer)
pb.RegisterDevopsServer(grpcServer, serverDevops)
// 注册ServerOpenchain服务器
serverOpenchain, err := rest.NewOpenchainServerWithPeerInfo(peerServer)
if err != nil {
err = fmt.Errorf("Error creating OpenchainServer: %s", err)
return err
}
pb.RegisterOpenchainServer(grpcServer, serverOpenchain)
// 如果配置了的话创建和注册REST服务
if viper.GetBool("rest.enabled") {
go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)
}
logger.Infof("Starting peer with ID=%s, network ID=%s, address=%s, rootnodes=%v, validator=%v",
peerEndpoint.ID, viper.GetString("peer.networkId"), peerEndpoint.Address,
viper.GetString("peer.discovery.rootnode"), peer.ValidatorEnabled())
// 启动GRPC服务器. 如果是必须的话在一个goroutine中完成这样我们能够部署genesis
serve := make(chan error)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
serve <- nil
}()
go func() {
var grpcErr error
if grpcErr = grpcServer.Serve(lis); grpcErr != nil {
grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)
} else {
logger.Info("grpc server exited")
}
serve <- grpcErr
}()
if err := writePid(viper.GetString("peer.fileSystemPath")+"/peer.pid", os.Getpid()); err != nil {
return err
}
// 启动eventHub服务
if ehubGrpcServer != nil && ehubLis != nil {
go ehubGrpcServer.Serve(ehubLis)
}
if viper.GetBool("peer.profile.enabled") {
go func() {
profileListenAddress := viper.GetString("peer.profile.listenAddress")
logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)
if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {
logger.Errorf("Error starting profiler: %s", profileErr)
}
}()
}
// Block until grpc server exits 产生块直到grpc服务退出
return <-serve
}
所过程在代码中的注释可以看明白
对图中peer节点启动之后的peer address 172.17.0.3:7051灰色部分的的代码提取分析,7051:peer gRPC 服务监听端口。下面是Hyperledger中相关监听的服务端口
默认包括:以下监听的服务端口对应hyperledger0.6版本,与其他版本无关。
7050: REST 服务端口
7051:peer gRPC 服务监听端口
7052:peer CLI 端口
7053:peer 事件服务端口
7054:eCAP7055:eCAA
7056:tCAP
7057:tCAA
7058:tlsCAP
7059:tlsCAA
图中的CacheConfiguration()这个函数到底做了什么?请看下面
// CacheConfiguration计算和缓存经常使用的常量且计算常量做为包变量,按照惯例前面的全局变量
// 已经被嵌入在这里为了保留原始的抽象状态
func CacheConfiguration() (err error) {
// getLocalAddress 返回正在操作的本地peer的address:port,受到env:peer.addressAutoDetect的影响
getLocalAddress := func() (peerAddress string, err error) {
if viper.GetBool("peer.addressAutoDetect") {
// 需要从peer.address设置中获取端口号,并将其添加到已经确定的主机ip后
_, port, err := net.SplitHostPort(viper.GetString("peer.address"))
if err != nil {
err = fmt.Errorf("Error auto detecting Peer's address: %s", err)
return "", err
}
peerAddress = net.JoinHostPort(GetLocalIP(), port)
peerLogger.Infof("Auto detected peer address: %s", peerAddress)
} else {
peerAddress = viper.GetString("peer.address")
}
return
}
// getPeerEndpoint 对于这个Peer实例来说,返回PeerEndpoint,受到env:peer.addressAutoDetect的影响
getPeerEndpoint := func() (*pb.PeerEndpoint, error) {
var peerAddress string
var peerType pb.PeerEndpoint_Type
peerAddress, err := getLocalAddress()
if err != nil {
return nil, err
}
if viper.GetBool("peer.validator.enabled") {
peerType = pb.PeerEndpoint_VALIDATOR
} else {
peerType = pb.PeerEndpoint_NON_VALIDATOR
}
return &pb.PeerEndpoint{ID: &pb.PeerID{Name: viper.GetString("peer.id")}, Address: peerAddress, Type: peerType}, nil
}
localAddress, localAddressError = getLocalAddress()
peerEndpoint, peerEndpointError = getPeerEndpoint()
syncStateSnapshotChannelSize = viper.GetInt("peer.sync.state.snapshot.channelSize")
syncStateDeltasChannelSize = viper.GetInt("peer.sync.state.deltas.channelSize")
syncBlocksChannelSize = viper.GetInt("peer.sync.blocks.channelSize")
validatorEnabled = viper.GetBool("peer.validator.enabled")
securityEnabled = viper.GetBool("security.enabled")
configurationCached = true
if localAddressError != nil {
return localAddressError
} else if peerEndpointError != nil {
return peerEndpointError
}
return
}
// cacheConfiguration如果检查失败打一个错误日志
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
} // GetPeerEndpoint 从缓存配置中返回peerEndpointfunc GetPeerEndpoint() (*pb.PeerEndpoint, error) {if !configurationCached {cacheConfiguration()}return peerEndpoint, peerEndpointError}
// cacheConfiguration如果检查失败打一个错误日志
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
由图片可以看出peer启动节点后先初始化一下日志
然后进入Server函数
//==============================================================================
//peer node start 之后做日志初始化之后就进入到server函数//==============================================================================
func serve(args []string) error {// Parameter overrides must be processed before any paramaters are// cached. Failures to cache cause the server to terminate immediately.//在其他参数被缓存起来之前参数覆盖必须处理,失败缓存导致服务立即结束if chaincodeDevMode {logger.Info("Running in chaincode development mode")logger.Info("Set consensus to NOOPS and user starts chaincode")logger.Info("Disable loading validity system chaincode")viper.Set("peer.validator.enabled", "true")viper.Set("peer.validator.consensus", "noops")viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)}if err := peer.CacheConfiguration(); err != nil {return err}peerEndpoint, err := peer.GetPeerEndpoint()if err != nil {err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)return err}//启动grpc服务,监听7051端口listenAddr := viper.GetString("peer.listenAddress")if "" == listenAddr {logger.Debug("Listen address not specified, using peer endpoint address")listenAddr = peerEndpoint.Address}lis, err := net.Listen("tcp", listenAddr)if err != nil {grpclog.Fatalf("Failed to listen: %v", err)}//创建EventHub服务器,通过调用createEventHubServer方法实现,该服务也是grpc,只有VP//才能开启ehubLis, ehubGrpcServer, err := createEventHubServer()if err != nil {grpclog.Fatalf("Failed to create ehub server: %v", err)}logger.Infof("Security enabled status: %t", core.SecurityEnabled())if viper.GetBool("security.privacy") {if core.SecurityEnabled() {logger.Infof("Privacy enabled status: true")} else {panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))}} else {logger.Infof("Privacy enabled status: false")}//启动rockdb数据库db.Start()var opts []grpc.ServerOptionif comm.TLSEnabled() {creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),viper.GetString("peer.tls.key.file"))if err != nil {grpclog.Fatalf("Failed to generate credentials %v", err)}opts = []grpc.ServerOption{grpc.Creds(creds)}}//创建一个grpc服务grpcServer := grpc.NewServer(opts...)//注册Chaincode支持服务器secHelper, err := getSecHelper()if err != nil {return err}secHelperFunc := func() crypto.Peer {return secHelper}registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)var peerServer *peer.Impl// 创建peer服务器,主意区分VP和NVP节点if peer.ValidatorEnabled() {logger.Debug("Running as validating peer - making genesis block if needed")makeGenesisError := genesis.MakeGenesis()if makeGenesisError != nil {return makeGenesisError}logger.Debugf("Running as validating peer - installing consensus %s",viper.GetString("peer.validator.consensus"))peerServer, err = peer.NewPeerWithEngine(secHelperFunc, helper.GetEngine)} else {logger.Debug("Running as non-validating peer")peerServer, err = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)}if err != nil {logger.Fatalf("Failed creating new peer with handler %v", err)return err}// 注册peer服务pb.RegisterPeerServer(grpcServer, peerServer)// 注册管理服务器pb.RegisterAdminServer(grpcServer, core.NewAdminServer())// 注册Devops服务器serverDevops := core.NewDevopsServer(peerServer)pb.RegisterDevopsServer(grpcServer, serverDevops)// 注册ServerOpenchain服务器serverOpenchain, err := rest.NewOpenchainServerWithPeerInfo(peerServer)if err != nil {err = fmt.Errorf("Error creating OpenchainServer: %s", err)return err}pb.RegisterOpenchainServer(grpcServer, serverOpenchain)// 如果配置了的话创建和注册REST服务if viper.GetBool("rest.enabled") {go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)}logger.Infof("Starting peer with ID=%s, network ID=%s, address=%s, rootnodes=%v, validator=%v",peerEndpoint.ID, viper.GetString("peer.networkId"), peerEndpoint.Address,viper.GetString("peer.discovery.rootnode"), peer.ValidatorEnabled())// 启动GRPC服务器. 如果是必须的话在一个goroutine中完成这样我们能够部署genesisserve := make(chan error)sigs := make(chan os.Signal, 1)signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)go func() {sig := <-sigsfmt.Println()fmt.Println(sig)serve <- nil}()go func() {var grpcErr errorif grpcErr = grpcServer.Serve(lis); grpcErr != nil {grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)} else {logger.Info("grpc server exited")}serve <- grpcErr}()if err := writePid(viper.GetString("peer.fileSystemPath")+"/peer.pid", os.Getpid()); err != nil {return err}// 启动eventHub服务if ehubGrpcServer != nil && ehubLis != nil {go ehubGrpcServer.Serve(ehubLis)}if viper.GetBool("peer.profile.enabled") {go func() {profileListenAddress := viper.GetString("peer.profile.listenAddress")logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {logger.Errorf("Error starting profiler: %s", profileErr)}}()}// Block until grpc server exits 产生块直到grpc服务退出return <-serve}
所过程在代码中的注释可以看明白对图中peer节点启动之后的peer address 172.17.0.3:7051灰色部分的的代码提取分析,7051:peer gRPC 服务监听端口。下面是Hyperledger中相关监听的服务端口
默认包括:以下监听的服务端口对应hyperledger0.6版本,与其他版本无关。
7050: REST 服务端口
7051:peer gRPC 服务监听端口
7052:peer CLI 端口
7053:peer 事件服务端口
7054:eCAP7055:eCAA
7056:tCAP
7057:tCAA
7058:tlsCAP
7059:tlsCAA
图中的CacheConfiguration()这个函数到底做了什么?请看下面
// CacheConfiguration计算和缓存经常使用的常量且计算常量做为包变量,按照惯例前面的全局变量
// 已经被嵌入在这里为了保留原始的抽象状态func CacheConfiguration() (err error) {// getLocalAddress 返回正在操作的本地peer的address:port,受到env:peer.addressAutoDetect的影响getLocalAddress := func() (peerAddress string, err error) {if viper.GetBool("peer.addressAutoDetect") {// 需要从peer.address设置中获取端口号,并将其添加到已经确定的主机ip后_, port, err := net.SplitHostPort(viper.GetString("peer.address"))if err != nil {err = fmt.Errorf("Error auto detecting Peer's address: %s", err)return "", err}peerAddress = net.JoinHostPort(GetLocalIP(), port)peerLogger.Infof("Auto detected peer address: %s", peerAddress)} else {peerAddress = viper.GetString("peer.address")}return}// getPeerEndpoint 对于这个Peer实例来说,返回PeerEndpoint,受到env:peer.addressAutoDetect的影响getPeerEndpoint := func() (*pb.PeerEndpoint, error) {var peerAddress stringvar peerType pb.PeerEndpoint_TypepeerAddress, err := getLocalAddress()if err != nil {return nil, err}if viper.GetBool("peer.validator.enabled") {peerType = pb.PeerEndpoint_VALIDATOR} else {peerType = pb.PeerEndpoint_NON_VALIDATOR}return &pb.PeerEndpoint{ID: &pb.PeerID{Name: viper.GetString("peer.id")}, Address: peerAddress, Type: peerType}, nil}localAddress, localAddressError = getLocalAddress()peerEndpoint, peerEndpointError = getPeerEndpoint()syncStateSnapshotChannelSize = viper.GetInt("peer.sync.state.snapshot.channelSize")syncStateDeltasChannelSize = viper.GetInt("peer.sync.state.deltas.channelSize")syncBlocksChannelSize = viper.GetInt("peer.sync.blocks.channelSize")validatorEnabled = viper.GetBool("peer.validator.enabled")securityEnabled = viper.GetBool("security.enabled")configurationCached = trueif localAddressError != nil {return localAddressError} else if peerEndpointError != nil {return peerEndpointError}return}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}} // GetPeerEndpoint 从缓存配置中返回peerEndpointfunc GetPeerEndpoint() (*pb.PeerEndpoint, error) {if !configurationCached {cacheConfiguration()}return peerEndpoint, peerEndpointError}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}如图所示,我们要分析的是registering BLOCK,registering CHAINCODE,registering REJECTION和registering REGISTER的整个过程
下图是代码流程图
func createEventHubServer() (net.Listener, *grpc.Server, error) {var lis net.Listenervar grpcServer *grpc.Servervar err error// ValidatorEnabled返回peer.validator.enabled是否可用if peer.ValidatorEnabled() {lis, err = net.Listen("tcp", viper.GetString("peer.validator.events.address"))if err != nil {return nil, nil, fmt.Errorf("failed to listen: %v", err)}//TODO - do we need different SSL material for events ?var opts []grpc.ServerOption// TLSEnabled返回peer.tls.enabled配置好的值的缓存值if comm.TLSEnabled() {//NewServerTLSFromFile是gRPC库的函数,主要目的是为获取tls的证书和密钥creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),viper.GetString("peer.tls.key.file"))if err != nil {return nil, nil, fmt.Errorf("Failed to generate credentials %v", err)}opts = []grpc.ServerOption{grpc.Creds(creds)}}grpcServer = grpc.NewServer(opts...)ehServer := producer.NewEventsServer(uint(viper.GetInt("peer.validator.events.buffersize")),viper.GetInt("peer.validator.events.timeout"))//注册事件服务pb.RegisterEventsServer(grpcServer, ehServer)}return lis, grpcServer, err}
// ValidatorEnabled返回peer.validator.enabled是否可用
func ValidatorEnabled() bool {if !configurationCached {cacheConfiguration()}return validatorEnabled}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}}
// TLSEnabled返回peer.tls.enabled配置好的值的缓存值func TLSEnabled() bool {if !configurationCached {cacheConfiguration()}return tlsEnabled}
// cacheConfiguration如果检查失败打错误日志.func cacheConfiguration() {if err := CacheConfiguration(); err != nil {commLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}}
// NewEventsServer 返回一个事件服务器func NewEventsServer(bufferSize uint, timeout int) *EventsServer {if globalEventsServer != nil {panic("Cannot create multiple event hub servers")}globalEventsServer = new(EventsServer)//初始化并且开启事件initializeEvents(bufferSize, timeout)//initializeCCEventProcessor(bufferSize, timeout)return globalEventsServer}
//初始化并且开启事件func initializeEvents(bufferSize uint, tout int) {if gEventProcessor != nil {panic("should not be called twice")}gEventProcessor = &eventProcessor{eventConsumers: make(map[pb.EventType]handlerList), eventChannel: make(chan *pb.Event, bufferSize), timeout: tout}addInternalEventTypes()//启动事件进程器go gEventProcessor.start()}
func addInternalEventTypes() {AddEventType(pb.EventType_BLOCK)AddEventType(pb.EventType_CHAINCODE)AddEventType(pb.EventType_REJECTION)AddEventType(pb.EventType_REGISTER)}
//AddEventType 添加支持的事件类型func AddEventType(eventType pb.EventType) error {gEventProcessor.Lock()producerLogger.Debugf("registering %s", pb.EventType_name[int32(eventType)])if _, ok := gEventProcessor.eventConsumers[eventType]; ok {gEventProcessor.Unlock()return fmt.Errorf("event type exists %s", pb.EventType_name[int32(eventType)])}switch eventType {case pb.EventType_BLOCK:gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}case pb.EventType_CHAINCODE:gEventProcessor.eventConsumers[eventType] = &chaincodeHandlerList{handlers: make(map[string]map[string]map[*handler]bool)}case pb.EventType_REJECTION:gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}}gEventProcessor.Unlock()return nil}
func (ep *eventProcessor) start() {producerLogger.Info("event processor started")for {//等待事件e := <-ep.eventChannelvar hl handlerListeType := getMessageType(e)ep.Lock()if hl, _ = ep.eventConsumers[eType]; hl == nil {producerLogger.Errorf("Event of type %s does not exist", eType)ep.Unlock()continue}//lock the handler map lockep.Unlock()hl.foreach(e, func(h *handler) {if e.Event != nil {h.SendMessage(e)}})}}
// 获取消息类型func getMessageType(e *pb.Event) pb.EventType {switch e.Event.(type) {case *pb.Event_Register:return pb.EventType_REGISTERcase *pb.Event_Block:return pb.EventType_BLOCKcase *pb.Event_ChaincodeEvent:return pb.EventType_CHAINCODEcase *pb.Event_Rejection:return pb.EventType_REJECTIONdefault:return -1}}
// SendMessage 通过流发送一条消息给远程的peerfunc (d *handler) SendMessage(msg *pb.Event) error {err := d.ChatStream.Send(msg)if err != nil {return fmt.Errorf("Error Sending message through ChatStream: %s", err)}return nil}
func RegisterEventsServer(s *grpc.Server, srv EventsServer) {
s.RegisterService(&_Events_serviceDesc, srv)}
一些重要的变量
type eventProcessor struct {
sync.RWMutexeventConsumers map[pb.EventType]handlerList//we could generalize this with mutiple channels each with its own size// 产生多个大小限定的channelseventChannel chan *pb.Event//milliseconds timeout for producer to send an event.//毫秒级别的超时触发器发送一个事件//if < 0, if buffer full, unblocks immediately and not send//如果小于0,如果缓冲区满的,立即解锁并且不发送事件//if 0, if buffer full, will block and guarantee the event will be sent out// 如是0,如果缓冲区满的,将上锁并保证事件不会被发出去//if > 0, if buffer full, blocks till timeout//如果是0,如果缓冲区是满的,上锁直到超时timeout int}
// 通过initializeEvents函数来创建全局eventProcessor单列模式 Openchain producers// Openchain仅仅通过一个重入的静态方法生产并发送事件var gEventProcessor *eventProcessortype EventType int32
const (EventType_REGISTER EventType = 0EventType_BLOCK EventType = 1EventType_CHAINCODE EventType = 2EventType_REJECTION EventType = 3)
var EventType_name = map[int32]string{0: "REGISTER",1: "BLOCK",2: "CHAINCODE",3: "REJECTION",}
var EventType_value = map[string]int32{"REGISTER": 0,"BLOCK": 1,"CHAINCODE": 2,"REJECTION": 3,}
// Event is used by
// - consumers (adapters) to send Register// - producer to advertise supported types and eventstype Event struct {// Types that are valid to be assigned to Event:// *Event_Register// *Event_Block// *Event_ChaincodeEvent// *Event_Rejection// *Event_UnregisterEvent isEvent_Event `protobuf_oneof:"Event"`}
由图片可以看出peer启动节点后先初始化一下日志
然后进入Server函数
//==============================================================================
//peer node start 之后做日志初始化之后就进入到server函数//==============================================================================
func serve(args []string) error {// Parameter overrides must be processed before any paramaters are// cached. Failures to cache cause the server to terminate immediately.//在其他参数被缓存起来之前参数覆盖必须处理,失败缓存导致服务立即结束if chaincodeDevMode {logger.Info("Running in chaincode development mode")logger.Info("Set consensus to NOOPS and user starts chaincode")logger.Info("Disable loading validity system chaincode")viper.Set("peer.validator.enabled", "true")viper.Set("peer.validator.consensus", "noops")viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)}if err := peer.CacheConfiguration(); err != nil {return err}peerEndpoint, err := peer.GetPeerEndpoint()if err != nil {err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)return err}//启动grpc服务,监听7051端口listenAddr := viper.GetString("peer.listenAddress")if "" == listenAddr {logger.Debug("Listen address not specified, using peer endpoint address")listenAddr = peerEndpoint.Address}lis, err := net.Listen("tcp", listenAddr)if err != nil {grpclog.Fatalf("Failed to listen: %v", err)}//创建EventHub服务器,通过调用createEventHubServer方法实现,该服务也是grpc,只有VP//才能开启ehubLis, ehubGrpcServer, err := createEventHubServer()if err != nil {grpclog.Fatalf("Failed to create ehub server: %v", err)}logger.Infof("Security enabled status: %t", core.SecurityEnabled())if viper.GetBool("security.privacy") {if core.SecurityEnabled() {logger.Infof("Privacy enabled status: true")} else {panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))}} else {logger.Infof("Privacy enabled status: false")}//启动rockdb数据库db.Start()var opts []grpc.ServerOptionif comm.TLSEnabled() {creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),viper.GetString("peer.tls.key.file"))if err != nil {grpclog.Fatalf("Failed to generate credentials %v", err)}opts = []grpc.ServerOption{grpc.Creds(creds)}}//创建一个grpc服务grpcServer := grpc.NewServer(opts...)//注册Chaincode支持服务器secHelper, err := getSecHelper()if err != nil {return err}secHelperFunc := func() crypto.Peer {return secHelper}registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)var peerServer *peer.Impl// 创建peer服务器,主意区分VP和NVP节点if peer.ValidatorEnabled() {logger.Debug("Running as validating peer - making genesis block if needed")makeGenesisError := genesis.MakeGenesis()if makeGenesisError != nil {return makeGenesisError}logger.Debugf("Running as validating peer - installing consensus %s",viper.GetString("peer.validator.consensus"))peerServer, err = peer.NewPeerWithEngine(secHelperFunc, helper.GetEngine)} else {logger.Debug("Running as non-validating peer")peerServer, err = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)}if err != nil {logger.Fatalf("Failed creating new peer with handler %v", err)return err}// 注册peer服务pb.RegisterPeerServer(grpcServer, peerServer)// 注册管理服务器pb.RegisterAdminServer(grpcServer, core.NewAdminServer())// 注册Devops服务器serverDevops := core.NewDevopsServer(peerServer)pb.RegisterDevopsServer(grpcServer, serverDevops)// 注册ServerOpenchain服务器serverOpenchain, err := rest.NewOpenchainServerWithPeerInfo(peerServer)if err != nil {err = fmt.Errorf("Error creating OpenchainServer: %s", err)return err}pb.RegisterOpenchainServer(grpcServer, serverOpenchain)// 如果配置了的话创建和注册REST服务if viper.GetBool("rest.enabled") {go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)}logger.Infof("Starting peer with ID=%s, network ID=%s, address=%s, rootnodes=%v, validator=%v",peerEndpoint.ID, viper.GetString("peer.networkId"), peerEndpoint.Address,viper.GetString("peer.discovery.rootnode"), peer.ValidatorEnabled())// 启动GRPC服务器. 如果是必须的话在一个goroutine中完成这样我们能够部署genesisserve := make(chan error)sigs := make(chan os.Signal, 1)signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)go func() {sig := <-sigsfmt.Println()fmt.Println(sig)serve <- nil}()go func() {var grpcErr errorif grpcErr = grpcServer.Serve(lis); grpcErr != nil {grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)} else {logger.Info("grpc server exited")}serve <- grpcErr}()if err := writePid(viper.GetString("peer.fileSystemPath")+"/peer.pid", os.Getpid()); err != nil {return err}// 启动eventHub服务if ehubGrpcServer != nil && ehubLis != nil {go ehubGrpcServer.Serve(ehubLis)}if viper.GetBool("peer.profile.enabled") {go func() {profileListenAddress := viper.GetString("peer.profile.listenAddress")logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {logger.Errorf("Error starting profiler: %s", profileErr)}}()}// Block until grpc server exits 产生块直到grpc服务退出return <-serve}
所过程在代码中的注释可以看明白对图中peer节点启动之后的peer address 172.17.0.3:7051灰色部分的的代码提取分析,7051:peer gRPC 服务监听端口。下面是Hyperledger中相关监听的服务端口
默认包括:以下监听的服务端口对应hyperledger0.6版本,与其他版本无关。
7050: REST 服务端口
7051:peer gRPC 服务监听端口
7052:peer CLI 端口
7053:peer 事件服务端口
7054:eCAP7055:eCAA
7056:tCAP
7057:tCAA
7058:tlsCAP
7059:tlsCAA
图中的CacheConfiguration()这个函数到底做了什么?请看下面
// CacheConfiguration计算和缓存经常使用的常量且计算常量做为包变量,按照惯例前面的全局变量
// 已经被嵌入在这里为了保留原始的抽象状态func CacheConfiguration() (err error) {// getLocalAddress 返回正在操作的本地peer的address:port,受到env:peer.addressAutoDetect的影响getLocalAddress := func() (peerAddress string, err error) {if viper.GetBool("peer.addressAutoDetect") {// 需要从peer.address设置中获取端口号,并将其添加到已经确定的主机ip后_, port, err := net.SplitHostPort(viper.GetString("peer.address"))if err != nil {err = fmt.Errorf("Error auto detecting Peer's address: %s", err)return "", err}peerAddress = net.JoinHostPort(GetLocalIP(), port)peerLogger.Infof("Auto detected peer address: %s", peerAddress)} else {peerAddress = viper.GetString("peer.address")}return}// getPeerEndpoint 对于这个Peer实例来说,返回PeerEndpoint,受到env:peer.addressAutoDetect的影响getPeerEndpoint := func() (*pb.PeerEndpoint, error) {var peerAddress stringvar peerType pb.PeerEndpoint_TypepeerAddress, err := getLocalAddress()if err != nil {return nil, err}if viper.GetBool("peer.validator.enabled") {peerType = pb.PeerEndpoint_VALIDATOR} else {peerType = pb.PeerEndpoint_NON_VALIDATOR}return &pb.PeerEndpoint{ID: &pb.PeerID{Name: viper.GetString("peer.id")}, Address: peerAddress, Type: peerType}, nil}localAddress, localAddressError = getLocalAddress()peerEndpoint, peerEndpointError = getPeerEndpoint()syncStateSnapshotChannelSize = viper.GetInt("peer.sync.state.snapshot.channelSize")syncStateDeltasChannelSize = viper.GetInt("peer.sync.state.deltas.channelSize")syncBlocksChannelSize = viper.GetInt("peer.sync.blocks.channelSize")validatorEnabled = viper.GetBool("peer.validator.enabled")securityEnabled = viper.GetBool("security.enabled")configurationCached = trueif localAddressError != nil {return localAddressError} else if peerEndpointError != nil {return peerEndpointError}return}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}} // GetPeerEndpoint 从缓存配置中返回peerEndpointfunc GetPeerEndpoint() (*pb.PeerEndpoint, error) {if !configurationCached {cacheConfiguration()}return peerEndpoint, peerEndpointError}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}如图所示,我们要分析的是registering BLOCK,registering CHAINCODE,registering REJECTION和registering REGISTER的整个过程
下图是代码流程图
func createEventHubServer() (net.Listener, *grpc.Server, error) {var lis net.Listenervar grpcServer *grpc.Servervar err error// ValidatorEnabled返回peer.validator.enabled是否可用if peer.ValidatorEnabled() {lis, err = net.Listen("tcp", viper.GetString("peer.validator.events.address"))if err != nil {return nil, nil, fmt.Errorf("failed to listen: %v", err)}//TODO - do we need different SSL material for events ?var opts []grpc.ServerOption// TLSEnabled返回peer.tls.enabled配置好的值的缓存值if comm.TLSEnabled() {//NewServerTLSFromFile是gRPC库的函数,主要目的是为获取tls的证书和密钥creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),viper.GetString("peer.tls.key.file"))if err != nil {return nil, nil, fmt.Errorf("Failed to generate credentials %v", err)}opts = []grpc.ServerOption{grpc.Creds(creds)}}grpcServer = grpc.NewServer(opts...)ehServer := producer.NewEventsServer(uint(viper.GetInt("peer.validator.events.buffersize")),viper.GetInt("peer.validator.events.timeout"))//注册事件服务pb.RegisterEventsServer(grpcServer, ehServer)}return lis, grpcServer, err}
// ValidatorEnabled返回peer.validator.enabled是否可用
func ValidatorEnabled() bool {if !configurationCached {cacheConfiguration()}return validatorEnabled}
// cacheConfiguration如果检查失败打一个错误日志func cacheConfiguration() {if err := CacheConfiguration(); err != nil {peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}}
// TLSEnabled返回peer.tls.enabled配置好的值的缓存值func TLSEnabled() bool {if !configurationCached {cacheConfiguration()}return tlsEnabled}
// cacheConfiguration如果检查失败打错误日志.func cacheConfiguration() {if err := CacheConfiguration(); err != nil {commLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)}}
// NewEventsServer 返回一个事件服务器func NewEventsServer(bufferSize uint, timeout int) *EventsServer {if globalEventsServer != nil {panic("Cannot create multiple event hub servers")}globalEventsServer = new(EventsServer)//初始化并且开启事件initializeEvents(bufferSize, timeout)//initializeCCEventProcessor(bufferSize, timeout)return globalEventsServer}
//初始化并且开启事件func initializeEvents(bufferSize uint, tout int) {if gEventProcessor != nil {panic("should not be called twice")}gEventProcessor = &eventProcessor{eventConsumers: make(map[pb.EventType]handlerList), eventChannel: make(chan *pb.Event, bufferSize), timeout: tout}addInternalEventTypes()//启动事件进程器go gEventProcessor.start()}
func addInternalEventTypes() {AddEventType(pb.EventType_BLOCK)AddEventType(pb.EventType_CHAINCODE)AddEventType(pb.EventType_REJECTION)AddEventType(pb.EventType_REGISTER)}
//AddEventType 添加支持的事件类型func AddEventType(eventType pb.EventType) error {gEventProcessor.Lock()producerLogger.Debugf("registering %s", pb.EventType_name[int32(eventType)])if _, ok := gEventProcessor.eventConsumers[eventType]; ok {gEventProcessor.Unlock()return fmt.Errorf("event type exists %s", pb.EventType_name[int32(eventType)])}switch eventType {case pb.EventType_BLOCK:gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}case pb.EventType_CHAINCODE:gEventProcessor.eventConsumers[eventType] = &chaincodeHandlerList{handlers: make(map[string]map[string]map[*handler]bool)}case pb.EventType_REJECTION:gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}}gEventProcessor.Unlock()return nil}
func (ep *eventProcessor) start() {producerLogger.Info("event processor started")for {//等待事件e := <-ep.eventChannelvar hl handlerListeType := getMessageType(e)ep.Lock()if hl, _ = ep.eventConsumers[eType]; hl == nil {producerLogger.Errorf("Event of type %s does not exist", eType)ep.Unlock()continue}//lock the handler map lockep.Unlock()hl.foreach(e, func(h *handler) {if e.Event != nil {h.SendMessage(e)}})}}
// 获取消息类型func getMessageType(e *pb.Event) pb.EventType {switch e.Event.(type) {case *pb.Event_Register:return pb.EventType_REGISTERcase *pb.Event_Block:return pb.EventType_BLOCKcase *pb.Event_ChaincodeEvent:return pb.EventType_CHAINCODEcase *pb.Event_Rejection:return pb.EventType_REJECTIONdefault:return -1}}
// SendMessage 通过流发送一条消息给远程的peerfunc (d *handler) SendMessage(msg *pb.Event) error {err := d.ChatStream.Send(msg)if err != nil {return fmt.Errorf("Error Sending message through ChatStream: %s", err)}return nil}
func RegisterEventsServer(s *grpc.Server, srv EventsServer) {
s.RegisterService(&_Events_serviceDesc, srv)}
一些重要的变量
type eventProcessor struct {
sync.RWMutexeventConsumers map[pb.EventType]handlerList//we could generalize this with mutiple channels each with its own size// 产生多个大小限定的channelseventChannel chan *pb.Event//milliseconds timeout for producer to send an event.//毫秒级别的超时触发器发送一个事件//if < 0, if buffer full, unblocks immediately and not send//如果小于0,如果缓冲区满的,立即解锁并且不发送事件//if 0, if buffer full, will block and guarantee the event will be sent out// 如是0,如果缓冲区满的,将上锁并保证事件不会被发出去//if > 0, if buffer full, blocks till timeout//如果是0,如果缓冲区是满的,上锁直到超时timeout int}
// 通过initializeEvents函数来创建全局eventProcessor单列模式 Openchain producers// Openchain仅仅通过一个重入的静态方法生产并发送事件var gEventProcessor *eventProcessortype EventType int32
const (EventType_REGISTER EventType = 0EventType_BLOCK EventType = 1EventType_CHAINCODE EventType = 2EventType_REJECTION EventType = 3)
var EventType_name = map[int32]string{0: "REGISTER",1: "BLOCK",2: "CHAINCODE",3: "REJECTION",}
var EventType_value = map[string]int32{"REGISTER": 0,"BLOCK": 1,"CHAINCODE": 2,"REJECTION": 3,}
// Event is used by
// - consumers (adapters) to send Register// - producer to advertise supported types and eventstype Event struct {// Types that are valid to be assigned to Event:// *Event_Register// *Event_Block// *Event_ChaincodeEvent// *Event_Rejection// *Event_UnregisterEvent isEvent_Event `protobuf_oneof:"Event"`}
我们都知道,Hyperledger用的数据库是rocksDB,如果你不做修改的话,数据会存储在/var/hyperledger/production/db目录下。
现在我们来分析一下图中灰色部分的相关代码。
代码结构图如下
// 启动数据库, 初始化openchainDB实例并打开数据库.注意该方法不能保证正确行为的并发调用
func Start() {openchainDB.open()}
// Open 打开已经存在于hyperledger中的数据库func (openchainDB *OpenchainDB) open() {dbPath := getDBPath()missing, err := dirMissingOrEmpty(dbPath)if err != nil {panic(fmt.Sprintf("Error while trying to open DB: %s", err))}dbLogger.Debugf("Is db path [%s] empty [%t]", dbPath, missing)if missing {err = os.MkdirAll(path.Dir(dbPath), 0755)if err != nil {panic(fmt.Sprintf("Error making directory path [%s]: %s", dbPath, err))}}opts := gorocksdb.NewDefaultOptions()defer opts.Destroy()maxLogFileSize := viper.GetInt("peer.db.maxLogFileSize")if maxLogFileSize > 0 {dbLogger.Infof("Setting rocksdb maxLogFileSize to %d", maxLogFileSize)opts.SetMaxLogFileSize(maxLogFileSize)}keepLogFileNum := viper.GetInt("peer.db.keepLogFileNum")if keepLogFileNum > 0 {dbLogger.Infof("Setting rocksdb keepLogFileNum to %d", keepLogFileNum)opts.SetKeepLogFileNum(keepLogFileNum)}logLevelStr := viper.GetString("peer.db.loglevel")logLevel, ok := rocksDBLogLevelMap[logLevelStr]if ok {dbLogger.Infof("Setting rocks db InfoLogLevel to %d", logLevel)opts.SetInfoLogLevel(logLevel)}opts.SetCreateIfMissing(missing)opts.SetCreateIfMissingColumnFamilies(true)cfNames := []string{"default"}cfNames = append(cfNames, columnfamilies...)var cfOpts []*gorocksdb.Optionsfor range cfNames {cfOpts = append(cfOpts, opts)}db, cfHandlers, err := gorocksdb.OpenDbColumnFamilies(opts, dbPath, cfNames, cfOpts)if err != nil {panic(fmt.Sprintf("Error opening DB: %s", err))}openchainDB.DB = dbopenchainDB.BlockchainCF = cfHandlers[1]openchainDB.StateCF = cfHandlers[2]openchainDB.StateDeltaCF = cfHandlers[3]openchainDB.IndexesCF = cfHandlers[4]openchainDB.PersistCF = cfHandlers[5]}
// NewDefaultOptions 创建一个默认的Options.func NewDefaultOptions() *Options {return NewNativeOptions(C.rocksdb_options_create())} // Options表示当以open形式打开一个数据库时所有可选的options// NewNativeOptions 创建一个Options对象.type Options struct {c *C.rocksdb_options_t// 保持引用GC.env *Envbbto *BlockBasedTableOptions// 在Destroy的时候我们要保证能够释放他们的内存ccmp *C.rocksdb_comparator_tcmo *C.rocksdb_mergeoperator_tcst *C.rocksdb_slicetransform_tccf *C.rocksdb_compactionfilter_t}
// NewDefaultOptions 创建一个默认的Options.func NewDefaultOptions() *Options {return NewNativeOptions(C.rocksdb_options_create())}
// NewNativeOptions 创建一个Options对象.func NewNativeOptions(c *C.rocksdb_options_t) *Options {return &Options{c: c}}
func NewNativeOptions(c *C.rocksdb_options_t) *Options {return &Options{c: c}}
// Options表示当以open形式打开一个数据库时所有可选的optionstype Options struct {c *C.rocksdb_options_t// 保持引用GC.env *Envbbto *BlockBasedTableOptions// 在Destroy的时候我们要保证能够释放他们的内存ccmp *C.rocksdb_comparator_tcmo *C.rocksdb_mergeoperator_tcst *C.rocksdb_slicetransform_tccf *C.rocksdb_compactionfilter_t}
// SetMaxLogFileSize 设置信息日志文件的最大尺寸// 如果日志文件大于max_log_file_size常量,新的日志将会被创建// 如果max_log_file_size等于0,所有的日志都被写到一个log日志// 默认大小:0func (opts *Options) SetMaxLogFileSize(value int) {C.rocksdb_options_set_max_log_file_size(opts.c, C.size_t(value))}
// SetKeepLogFileNum 设置保存的最大日志信息文件// 默认大小: 1000func (opts *Options) SetKeepLogFileNum(value int) {C.rocksdb_options_set_keep_log_file_num(opts.c, C.size_t(value))}
// SetInfoLogLevel 设置日志信息的级别.// 默认级别: InfoInfoLogLevelfunc (opts *Options) SetInfoLogLevel(value InfoLogLevel) {C.rocksdb_options_set_info_log_level(opts.c, C.int(value))}
// InfoLogLevel描述日志级别.type InfoLogLevel uint// 日志级别.const (DebugInfoLogLevel = InfoLogLevel(0)InfoInfoLogLevel = InfoLogLevel(1)WarnInfoLogLevel = InfoLogLevel(2)ErrorInfoLogLevel = InfoLogLevel(3)FatalInfoLogLevel = InfoLogLevel(4))
// SetCreateIfMissing 如果数据库丢失了指定数据库是不是应该被创建// 默认值: falsefunc (opts *Options) SetCreateIfMissing(value bool) {C.rocksdb_options_set_create_if_missing(opts.c, boolToChar(value))}
// SetCreateIfMissingColumnFamilies 如果指定的列丢失啦是不是应该被创建func (opts *Options) SetCreateIfMissingColumnFamilies(value bool) {C.rocksdb_options_set_create_missing_column_families(opts.c, boolToChar(value))}
// 打开列家族db, cfHandlers, err := gorocksdb.OpenDbColumnFamilies(opts, dbPath, cfNames, cfOpts)
由图片可以看出peer启动节点后先初始化一下日志
然后进入Server函数
//==============================================================================
//peer node start 之后做日志初始化之后就进入到server函数
//==============================================================================
func serve(args []string) error {
// Parameter overrides must be processed before any paramaters are
// cached. Failures to cache cause the server to terminate immediately.
//在其他参数被缓存起来之前参数覆盖必须处理,失败缓存导致服务立即结束
if chaincodeDevMode {
logger.Info("Running in chaincode development mode")
logger.Info("Set consensus to NOOPS and user starts chaincode")
logger.Info("Disable loading validity system chaincode")
viper.Set("peer.validator.enabled", "true")
viper.Set("peer.validator.consensus", "noops")
viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)
}
if err := peer.CacheConfiguration(); err != nil {
return err
}
peerEndpoint, err := peer.GetPeerEndpoint()
if err != nil {
err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)
return err
}
//启动grpc服务,监听7051端口
listenAddr := viper.GetString("peer.listenAddress")
if "" == listenAddr {
logger.Debug("Listen address not specified, using peer endpoint address")
listenAddr = peerEndpoint.Address
}
lis, err := net.Listen("tcp", listenAddr)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
//创建EventHub服务器,通过调用createEventHubServer方法实现,该服务也是grpc,只有VP
//才能开启
ehubLis, ehubGrpcServer, err := createEventHubServer()
if err != nil {
grpclog.Fatalf("Failed to create ehub server: %v", err)
}
logger.Infof("Security enabled status: %t", core.SecurityEnabled())
if viper.GetBool("security.privacy") {
if core.SecurityEnabled() {
logger.Infof("Privacy enabled status: true")
} else {
panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))
}
} else {
logger.Infof("Privacy enabled status: false")
}
//启动rockdb数据库
db.Start()
var opts []grpc.ServerOption
if comm.TLSEnabled() {
creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"),
viper.GetString("peer.tls.key.file"))
if err != nil {
grpclog.Fatalf("Failed to generate credentials %v", err)
}
opts = []grpc.ServerOption{grpc.Creds(creds)}
}
//创建一个grpc服务
grpcServer := grpc.NewServer(opts...)
//注册Chaincode支持服务器
secHelper, err := getSecHelper()
if err != nil {
return err
}
secHelperFunc := func() crypto.Peer {
return secHelper
}
registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)
var peerServer *peer.Impl
// 创建peer服务器,主意区分VP和NVP节点
if peer.ValidatorEnabled() {
logger.Debug("Running as validating peer - making genesis block if needed")
makeGenesisError := genesis.MakeGenesis()
if makeGenesisError != nil {
return makeGenesisError
}
logger.Debugf("Running as validating peer - installing consensus %s",
viper.GetString("peer.validator.consensus"))
peerServer, err = peer.NewPeerWithEngine(secHelperFunc, helper.GetEngine)
} else {
logger.Debug("Running as non-validating peer")
peerServer, err = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)
}
if err != nil {
logger.Fatalf("Failed creating new peer with handler %v", err)
return err
}
// 注册peer服务
pb.RegisterPeerServer(grpcServer, peerServer)
// 注册管理服务器
pb.RegisterAdminServer(grpcServer, core.NewAdminServer())
// 注册Devops服务器
serverDevops := core.NewDevopsServer(peerServer)
pb.RegisterDevopsServer(grpcServer, serverDevops)
// 注册ServerOpenchain服务器
serverOpenchain, err := rest.NewOpenchainServerWithPeerInfo(peerServer)
if err != nil {
err = fmt.Errorf("Error creating OpenchainServer: %s", err)
return err
}
pb.RegisterOpenchainServer(grpcServer, serverOpenchain)
// 如果配置了的话创建和注册REST服务
if viper.GetBool("rest.enabled") {
go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)
}
logger.Infof("Starting peer with ID=%s, network ID=%s, address=%s, rootnodes=%v, validator=%v",
peerEndpoint.ID, viper.GetString("peer.networkId"), peerEndpoint.Address,
viper.GetString("peer.discovery.rootnode"), peer.ValidatorEnabled())
// 启动GRPC服务器. 如果是必须的话在一个goroutine中完成这样我们能够部署genesis
serve := make(chan error)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
serve <- nil
}()
go func() {
var grpcErr error
if grpcErr = grpcServer.Serve(lis); grpcErr != nil {
grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)
} else {
logger.Info("grpc server exited")
}
serve <- grpcErr
}()
if err := writePid(viper.GetString("peer.fileSystemPath")+"/peer.pid", os.Getpid()); err != nil {
return err
}
// 启动eventHub服务
if ehubGrpcServer != nil && ehubLis != nil {
go ehubGrpcServer.Serve(ehubLis)
}
if viper.GetBool("peer.profile.enabled") {
go func() {
profileListenAddress := viper.GetString("peer.profile.listenAddress")
logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)
if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {
logger.Errorf("Error starting profiler: %s", profileErr)
}
}()
}
// Block until grpc server exits 产生块直到grpc服务退出
return <-serve
}
所过程在代码中的注释可以看明白
对图中peer节点启动之后的peer address 172.17.0.3:7051灰色部分的的代码提取分析,7051:peer gRPC 服务监听端口。下面是Hyperledger中相关监听的服务端口
默认包括:以下监听的服务端口对应hyperledger0.6版本,与其他版本无关。
7050: REST 服务端口
7051:peer gRPC 服务监听端口
7052:peer CLI 端口
7053:peer 事件服务端口
7054:eCAP7055:eCAA
7056:tCAP
7057:tCAA
7058:tlsCAP
7059:tlsCAA
图中的CacheConfiguration()这个函数到底做了什么?请看下面
// CacheConfiguration计算和缓存经常使用的常量且计算常量做为包变量,按照惯例前面的全局变量
// 已经被嵌入在这里为了保留原始的抽象状态
func CacheConfiguration() (err error) {
// getLocalAddress 返回正在操作的本地peer的address:port,受到env:peer.addressAutoDetect的影响
getLocalAddress := func() (peerAddress string, err error) {
if viper.GetBool("peer.addressAutoDetect") {
// 需要从peer.address设置中获取端口号,并将其添加到已经确定的主机ip后
_, port, err := net.SplitHostPort(viper.GetString("peer.address"))
if err != nil {
err = fmt.Errorf("Error auto detecting Peer's address: %s", err)
return "", err
}
peerAddress = net.JoinHostPort(GetLocalIP(), port)
peerLogger.Infof("Auto detected peer address: %s", peerAddress)
} else {
peerAddress = viper.GetString("peer.address")
}
return
}
// getPeerEndpoint 对于这个Peer实例来说,返回PeerEndpoint,受到env:peer.addressAutoDetect的影响
getPeerEndpoint := func() (*pb.PeerEndpoint, error) {
var peerAddress string
var peerType pb.PeerEndpoint_Type
peerAddress, err := getLocalAddress()
if err != nil {
return nil, err
}
if viper.GetBool("peer.validator.enabled") {
peerType = pb.PeerEndpoint_VALIDATOR
} else {
peerType = pb.PeerEndpoint_NON_VALIDATOR
}
return &pb.PeerEndpoint{ID: &pb.PeerID{Name: viper.GetString("peer.id")}, Address: peerAddress, Type: peerType}, nil
}
localAddress, localAddressError = getLocalAddress()
peerEndpoint, peerEndpointError = getPeerEndpoint()
syncStateSnapshotChannelSize = viper.GetInt("peer.sync.state.snapshot.channelSize")
syncStateDeltasChannelSize = viper.GetInt("peer.sync.state.deltas.channelSize")
syncBlocksChannelSize = viper.GetInt("peer.sync.blocks.channelSize")
validatorEnabled = viper.GetBool("peer.validator.enabled")
securityEnabled = viper.GetBool("security.enabled")
configurationCached = true
if localAddressError != nil {
return localAddressError
} else if peerEndpointError != nil {
return peerEndpointError
}
return
}
// cacheConfiguration如果检查失败打一个错误日志
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
} // GetPeerEndpoint 从缓存配置中返回peerEndpointfunc GetPeerEndpoint() (*pb.PeerEndpoint, error) {if !configurationCached {cacheConfiguration()}return peerEndpoint, peerEndpointError}
// cacheConfiguration如果检查失败打一个错误日志
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
如图所示,我们要分析的是registering BLOCK,registering CHAINCODE,registering REJECTION和registering REGISTER的整个过程
下图是代码流程图
func createEventHubServer() (net.Listener, *grpc.Server, error) {
var lis net.Listener
var grpcServer *grpc.Server
var err error
// ValidatorEnabled返回peer.validator.enabled是否可用
if peer.ValidatorEnabled() {
lis, err = net.Listen("tcp", viper.GetString("peer.validator.events.address"))
if err != nil {
return nil, nil, fmt.Errorf("failed to listen: %v", err)
}
//TODO - do we need different SSL material for events ?
var opts []grpc.ServerOption
// TLSEnabled返回peer.tls.enabled配置好的值的缓存值
if comm.TLSEnabled() {
//NewServerTLSFromFile是gRPC库的函数,主要目的是为获取tls的证书和密钥
creds, err := credentials.NewServerTLSFromFile(
viper.GetString("peer.tls.cert.file"),
viper.GetString("peer.tls.key.file"))
if err != nil {
return nil, nil, fmt.Errorf("Failed to generate credentials %v", err)
}
opts = []grpc.ServerOption{grpc.Creds(creds)}
}
grpcServer = grpc.NewServer(opts...)
ehServer := producer.NewEventsServer(
uint(viper.GetInt("peer.validator.events.buffersize")),
viper.GetInt("peer.validator.events.timeout"))
//注册事件服务
pb.RegisterEventsServer(grpcServer, ehServer)
}
return lis, grpcServer, err
}
// ValidatorEnabled返回peer.validator.enabled是否可用
func ValidatorEnabled() bool {
if !configurationCached {
cacheConfiguration()
}
return validatorEnabled
}
//
cacheConfiguration如果检查失败打一个错误日志
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
peerLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
}
//
TLSEnabled返回peer.tls.enabled配置好的值的缓存值
func TLSEnabled() bool {
if !configurationCached {
cacheConfiguration()
}
return tlsEnabled
}
//
cacheConfiguration如果检查失败打错误日志.
func cacheConfiguration() {
if err := CacheConfiguration(); err != nil {
commLogger.Errorf("Execution continues after CacheConfiguration() failure : %s", err)
}
}
//
NewEventsServer
返回一个事件服务器
func NewEventsServer(bufferSize uint, timeout int) *EventsServer {
if globalEventsServer != nil {
panic("Cannot create multiple event hub servers")
}
globalEventsServer = new(EventsServer)
//初始化并且开启事件
initializeEvents(bufferSize, timeout)
//initializeCCEventProcessor(bufferSize, timeout)
return globalEventsServer
}
//初始化并且开启事件
func initializeEvents(bufferSize uint, tout int) {
if gEventProcessor != nil {
panic("should not be called twice")
}
gEventProcessor = &eventProcessor{eventConsumers: make(map[pb.EventType]handlerList), eventChannel: make(chan *pb.Event, bufferSize), timeout: tout}
addInternalEventTypes()
//启动事件进程器
go gEventProcessor.start()
}
func
addInternalEventTypes()
{
AddEventType(pb.EventType_BLOCK)
AddEventType(pb.EventType_CHAINCODE)
AddEventType(pb.EventType_REJECTION)
AddEventType(pb.EventType_REGISTER)
}
//AddEventType
添加支持的事件类型
func AddEventType(eventType pb.EventType) error {
gEventProcessor.Lock()
producerLogger.Debugf("registering %s", pb.EventType_name[int32(eventType)])
if _, ok := gEventProcessor.eventConsumers[eventType]; ok {
gEventProcessor.Unlock()
return fmt.Errorf("event type exists %s", pb.EventType_name[int32(eventType)])
}
switch eventType {
case pb.EventType_BLOCK:
gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}
case pb.EventType_CHAINCODE:
gEventProcessor.eventConsumers[eventType] = &chaincodeHandlerList{handlers: make(map[string]map[string]map[*handler]bool)}
case pb.EventType_REJECTION:
gEventProcessor.eventConsumers[eventType] = &genericHandlerList{handlers: make(map[*handler]bool)}
}
gEventProcessor.Unlock()
return nil
}
func
(
ep
*
eventProcessor
)
start()
{
producerLogger.Info("event processor started")
for {
//等待事件
e := <-ep.eventChannel
var hl handlerList
eType := getMessageType(e)
ep.Lock()
if hl, _ = ep.eventConsumers[eType]; hl == nil {
producerLogger.Errorf("Event of type %s does not exist", eType)
ep.Unlock()
continue
}
//lock the handler map lock
ep.Unlock()
hl.foreach(e, func(h *handler) {
if e.Event != nil {
h.SendMessage(e)
}
})
}
}
//
获取消息类型
func getMessageType(e *pb.Event) pb.EventType {
switch e.Event.(type) {
case *pb.Event_Register:
return pb.EventType_REGISTER
case *pb.Event_Block:
return pb.EventType_BLOCK
case *pb.Event_ChaincodeEvent:
return pb.EventType_CHAINCODE
case *pb.Event_Rejection:
return pb.EventType_REJECTION
default:
return -1
}
}
//
SendMessage
通过流发送一条消息给远程的peer
func (d *handler) SendMessage(msg *pb.Event) error {
err := d.ChatStream.Send(msg)
if err != nil {
return fmt.Errorf("Error Sending message through ChatStream: %s", err)
}
return nil
}
func RegisterEventsServer(s *grpc.Server, srv EventsServer) {
s.RegisterService(&_Events_serviceDesc, srv)
}
一些重要的变量
type eventProcessor struct {
sync.RWMutex
eventConsumers map[pb.EventType]handlerList
//we could generalize this with mutiple channels each with its own size
// 产生多个大小限定的channels
eventChannel chan *pb.Event
//milliseconds timeout for producer to send an event.
//毫秒级别的超时触发器发送一个事件
//if < 0, if buffer full, unblocks immediately and not send
//如果小于0,如果缓冲区满的,立即解锁并且不发送事件
//if 0, if buffer full, will block and guarantee the event will be sent out
// 如是0,如果缓冲区满的,将上锁并保证事件不会被发出去
//if > 0, if buffer full, blocks till timeout
//如果是0,如果缓冲区是满的,上锁直到超时
timeout int
}
// 通过initializeEvents函数来创建全局eventProcessor单列模式 Openchain producers
// Openchain仅仅通过一个重入的静态方法生产并发送事件
var gEventProcessor *eventProcessor
type EventType int32
const (
EventType_REGISTER EventType = 0
EventType_BLOCK EventType = 1
EventType_CHAINCODE EventType = 2
EventType_REJECTION EventType = 3
)
var EventType_name = map[int32]string{
0: "REGISTER",
1: "BLOCK",
2: "CHAINCODE",
3: "REJECTION",
}
var EventType_value = map[string]int32{
"REGISTER": 0,
"BLOCK": 1,
"CHAINCODE": 2,
"REJECTION": 3,
}
// Event is used by
// - consumers (adapters) to send Register
// - producer to advertise supported types and events
type Event struct {
// Types that are valid to be assigned to Event:
// *Event_Register
// *Event_Block
// *Event_ChaincodeEvent
// *Event_Rejection
// *Event_Unregister
Event isEvent_Event `protobuf_oneof:"Event"`
}
我们都知道,Hyperledger用的数据库是rocksDB,如果你不做修改的话,数据会存储在/var/hyperledger/production/db目录下。
现在我们来分析一下图中灰色部分的相关代码。
代码结构图如下
// 启动数据库, 初始化openchainDB实例并打开数据库.注意该方法不能保证正确行为的并发调用
func Start() {
openchainDB.open()
}
//
Open
打开已经存在于hyperledger中的数据库
func (openchainDB *OpenchainDB) open() {
dbPath := getDBPath()
missing, err := dirMissingOrEmpty(dbPath)
if err != nil {
panic(fmt.Sprintf("Error while trying to open DB: %s", err))
}
dbLogger.Debugf("Is db path [%s] empty [%t]", dbPath, missing)
if missing {
err = os.MkdirAll(path.Dir(dbPath), 0755)
if err != nil {
panic(fmt.Sprintf("Error making directory path [%s]: %s", dbPath, err))
}
}
opts := gorocksdb.NewDefaultOptions()
defer opts.Destroy()
maxLogFileSize := viper.GetInt("peer.db.maxLogFileSize")
if maxLogFileSize > 0 {
dbLogger.Infof("Setting rocksdb maxLogFileSize to %d", maxLogFileSize)
opts.SetMaxLogFileSize(maxLogFileSize)
}
keepLogFileNum := viper.GetInt("peer.db.keepLogFileNum")
if keepLogFileNum > 0 {
dbLogger.Infof("Setting rocksdb keepLogFileNum to %d", keepLogFileNum)
opts.SetKeepLogFileNum(keepLogFileNum)
}
logLevelStr := viper.GetString("peer.db.loglevel")
logLevel, ok := rocksDBLogLevelMap[logLevelStr]
if ok {
dbLogger.Infof("Setting rocks db InfoLogLevel to %d", logLevel)
opts.SetInfoLogLevel(logLevel)
}
opts.SetCreateIfMissing(missing)
opts.SetCreateIfMissingColumnFamilies(true)
cfNames := []string{"default"}
cfNames = append(cfNames, columnfamilies...)
var cfOpts []*gorocksdb.Options
for range cfNames {
cfOpts = append(cfOpts, opts)
}
db, cfHandlers, err := gorocksdb.OpenDbColumnFamilies(opts, dbPath, cfNames, cfOpts)
if err != nil {
panic(fmt.Sprintf("Error opening DB: %s", err))
}
openchainDB.DB = db
openchainDB.BlockchainCF = cfHandlers[1]
openchainDB.StateCF = cfHandlers[2]
openchainDB.StateDeltaCF = cfHandlers[3]
openchainDB.IndexesCF = cfHandlers[4]
openchainDB.PersistCF = cfHandlers[5]
}
//
NewDefaultOptions
创建一个默认的Options.
func NewDefaultOptions() *Options {
return NewNativeOptions(C.rocksdb_options_create())
} // Options表示当以open形式打开一个数据库时所有可选的options// NewNativeOptions 创建一个Options对象.type Options struct {c *C.rocksdb_options_t// 保持引用GC.env *Envbbto *BlockBasedTableOptions// 在Destroy的时候我们要保证能够释放他们的内存ccmp *C.rocksdb_comparator_tcmo *C.rocksdb_mergeoperator_tcst *C.rocksdb_slicetransform_tccf *C.rocksdb_compactionfilter_t}
// NewDefaultOptions 创建一个默认的Options.func NewDefaultOptions() *Options {return NewNativeOptions(C.rocksdb_options_create())}
// NewNativeOptions 创建一个Options对象.func NewNativeOptions(c *C.rocksdb_options_t) *Options {return &Options{c: c}}
func NewNativeOptions(c *C.rocksdb_options_t) *Options {
return &Options{c: c}
}
//
Options表示当以open形式打开一个数据库时所有可选的options
type Options struct {
c *C.rocksdb_options_t
// 保持引用GC.
env *Env
bbto *BlockBasedTableOptions
// 在Destroy的时候我们要保证能够释放他们的内存
ccmp *C.rocksdb_comparator_t
cmo *C.rocksdb_mergeoperator_t
cst *C.rocksdb_slicetransform_t
ccf *C.rocksdb_compactionfilter_t
}
//
SetMaxLogFileSize
设置信息日志文件的最大尺寸
// 如果日志文件大于max_log_file_size常量,新的日志将会被创建
// 如果max_log_file_size等于0,所有的日志都被写到一个log日志
// 默认大小:0
func (opts *Options) SetMaxLogFileSize(value int) {
C.rocksdb_options_set_max_log_file_size(opts.c, C.size_t(value))
}
//
SetKeepLogFileNum
设置保存的最大日志信息文件
// 默认大小: 1000
func (opts *Options) SetKeepLogFileNum(value int) {
C.rocksdb_options_set_keep_log_file_num(opts.c, C.size_t(value))
}
//
SetInfoLogLevel
设置日志信息的级别.
// 默认级别: InfoInfoLogLevel
func (opts *Options) SetInfoLogLevel(value InfoLogLevel) {
C.rocksdb_options_set_info_log_level(opts.c, C.int(value))
}
//
InfoLogLevel描述日志级别.
type InfoLogLevel uint
// 日志级别.
const (
DebugInfoLogLevel = InfoLogLevel(0)
InfoInfoLogLevel = InfoLogLevel(1)
WarnInfoLogLevel = InfoLogLevel(2)
ErrorInfoLogLevel = InfoLogLevel(3)
FatalInfoLogLevel = InfoLogLevel(4)
)
//
SetCreateIfMissing
如果数据库丢失了指定数据库是不是应该被创建
// 默认值: false
func (opts *Options) SetCreateIfMissing(value bool) {
C.rocksdb_options_set_create_if_missing(opts.c, boolToChar(value))
}
//
SetCreateIfMissingColumnFamilies
如果指定的列丢失啦是不是应该被创建
func (opts *Options) SetCreateIfMissingColumnFamilies(value bool) {
C.rocksdb_options_set_create_missing_column_families(opts.c, boolToChar(value))
}
//
打开列家族
db, cfHandlers, err := gorocksdb.OpenDbColumnFamilies(opts, dbPath, cfNames, cfOpts)