2018-10-08 23:15:54 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package sdbclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2018-11-09 13:32:35 +00:00
|
|
|
monkit "gopkg.in/spacemonkeygo/monkit.v2"
|
2018-10-08 23:15:54 +01:00
|
|
|
|
|
|
|
"storj.io/storj/pkg/provider"
|
|
|
|
pb "storj.io/storj/pkg/statdb/proto"
|
2018-11-09 13:32:35 +00:00
|
|
|
"storj.io/storj/pkg/transport"
|
2018-10-08 23:15:54 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
mon = monkit.Package()
|
|
|
|
)
|
|
|
|
|
|
|
|
// StatDB creates a grpcClient
|
|
|
|
type StatDB struct {
|
2018-11-06 17:49:17 +00:00
|
|
|
client pb.StatDBClient
|
|
|
|
APIKey []byte
|
2018-10-08 23:15:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Client services offerred for the interface
|
|
|
|
type Client interface {
|
|
|
|
Create(ctx context.Context, nodeID []byte) error
|
|
|
|
Get(ctx context.Context, nodeID []byte) (*pb.NodeStats, error)
|
2018-10-30 17:11:22 +00:00
|
|
|
FindValidNodes(ctx context.Context, nodeIDs [][]byte, minAuditCount int64,
|
2018-10-31 16:18:51 +00:00
|
|
|
minAuditSuccess, minUptime float64) (passedIDs [][]byte, err error)
|
2018-10-08 23:15:54 +01:00
|
|
|
Update(ctx context.Context, nodeID []byte, auditSuccess, isUp bool, latencyList []int64,
|
|
|
|
updateAuditSuccess, updateUptime, updateLatency bool) (*pb.NodeStats, error)
|
2018-10-16 18:40:34 +01:00
|
|
|
UpdateBatch(ctx context.Context, nodes []*pb.Node) ([]*pb.NodeStats, []*pb.Node, error)
|
|
|
|
CreateEntryIfNotExists(ctx context.Context, node *pb.Node) (stats *pb.NodeStats, err error)
|
2018-10-08 23:15:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewClient initializes a new statdb client
|
2018-11-06 17:49:17 +00:00
|
|
|
func NewClient(identity *provider.FullIdentity, address string, APIKey []byte) (Client, error) {
|
|
|
|
tc := transport.NewClient(identity)
|
|
|
|
conn, err := tc.DialAddress(context.Background(), address)
|
2018-10-08 23:15:54 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &StatDB{
|
2018-11-06 17:49:17 +00:00
|
|
|
client: pb.NewStatDBClient(conn),
|
|
|
|
APIKey: APIKey,
|
2018-10-08 23:15:54 +01:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// a compiler trick to make sure *StatDB implements Client
|
|
|
|
var _ Client = (*StatDB)(nil)
|
|
|
|
|
|
|
|
// Create is used for creating a new entry in the stats db
|
|
|
|
func (sdb *StatDB) Create(ctx context.Context, nodeID []byte) (err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
node := pb.Node{
|
|
|
|
NodeId: nodeID,
|
|
|
|
UpdateAuditSuccess: false,
|
|
|
|
UpdateUptime: false,
|
|
|
|
}
|
|
|
|
createReq := &pb.CreateRequest{
|
|
|
|
Node: &node,
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
2018-11-06 17:49:17 +00:00
|
|
|
_, err = sdb.client.Create(ctx, createReq)
|
2018-10-08 23:15:54 +01:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get is used for retrieving a new entry from the stats db
|
|
|
|
func (sdb *StatDB) Get(ctx context.Context, nodeID []byte) (stats *pb.NodeStats, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
getReq := &pb.GetRequest{
|
|
|
|
NodeId: nodeID,
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
2018-11-06 17:49:17 +00:00
|
|
|
res, err := sdb.client.Get(ctx, getReq)
|
2018-11-07 01:16:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-08 23:15:54 +01:00
|
|
|
|
|
|
|
return res.Stats, err
|
|
|
|
}
|
|
|
|
|
2018-10-30 17:11:22 +00:00
|
|
|
// FindValidNodes is used for retrieving a subset of nodes that meet a minimum reputation requirement
|
|
|
|
func (sdb *StatDB) FindValidNodes(ctx context.Context, nodeIDs [][]byte, minAuditCount int64,
|
2018-10-31 16:18:51 +00:00
|
|
|
minAuditSuccess, minUptime float64) (passedIDs [][]byte, err error) {
|
2018-10-30 17:11:22 +00:00
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
findValidNodesReq := &pb.FindValidNodesRequest{
|
|
|
|
NodeIds: nodeIDs,
|
|
|
|
MinStats: &pb.NodeStats{
|
|
|
|
AuditSuccessRatio: minAuditSuccess,
|
|
|
|
UptimeRatio: minUptime,
|
|
|
|
AuditCount: minAuditCount,
|
|
|
|
},
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:49:17 +00:00
|
|
|
res, err := sdb.client.FindValidNodes(ctx, findValidNodesReq)
|
2018-10-30 17:11:22 +00:00
|
|
|
if err != nil {
|
2018-10-31 16:18:51 +00:00
|
|
|
return nil, err
|
2018-10-30 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2018-10-31 16:18:51 +00:00
|
|
|
return res.PassedIds, nil
|
2018-10-30 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2018-10-08 23:15:54 +01:00
|
|
|
// Update is used for updating a node's stats in the stats db
|
|
|
|
func (sdb *StatDB) Update(ctx context.Context, nodeID []byte, auditSuccess, isUp bool, latencyList []int64,
|
|
|
|
updateAuditSuccess, updateUptime, updateLatency bool) (stats *pb.NodeStats, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
node := pb.Node{
|
|
|
|
NodeId: nodeID,
|
|
|
|
AuditSuccess: auditSuccess,
|
|
|
|
IsUp: isUp,
|
|
|
|
LatencyList: latencyList,
|
|
|
|
UpdateAuditSuccess: updateAuditSuccess,
|
|
|
|
UpdateUptime: updateUptime,
|
|
|
|
UpdateLatency: updateLatency,
|
|
|
|
}
|
|
|
|
updateReq := &pb.UpdateRequest{
|
|
|
|
Node: &node,
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:49:17 +00:00
|
|
|
res, err := sdb.client.Update(ctx, updateReq)
|
2018-11-07 01:16:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-08 23:15:54 +01:00
|
|
|
|
|
|
|
return res.Stats, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateBatch is used for updating multiple nodes' stats in the stats db
|
2018-10-16 18:40:34 +01:00
|
|
|
func (sdb *StatDB) UpdateBatch(ctx context.Context, nodes []*pb.Node) (statsList []*pb.NodeStats, failedNodes []*pb.Node, err error) {
|
2018-10-08 23:15:54 +01:00
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
updateBatchReq := &pb.UpdateBatchRequest{
|
|
|
|
NodeList: nodes,
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:49:17 +00:00
|
|
|
res, err := sdb.client.UpdateBatch(ctx, updateBatchReq)
|
2018-11-07 01:16:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2018-10-08 23:15:54 +01:00
|
|
|
|
2018-10-16 18:40:34 +01:00
|
|
|
return res.StatsList, res.FailedNodes, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateEntryIfNotExists creates a db entry for a node if entry doesn't already exist
|
|
|
|
func (sdb *StatDB) CreateEntryIfNotExists(ctx context.Context, node *pb.Node) (stats *pb.NodeStats, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
createReq := &pb.CreateEntryIfNotExistsRequest{
|
|
|
|
Node: node,
|
|
|
|
APIKey: sdb.APIKey,
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:49:17 +00:00
|
|
|
res, err := sdb.client.CreateEntryIfNotExists(ctx, createReq)
|
2018-11-07 01:16:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-16 18:40:34 +01:00
|
|
|
|
|
|
|
return res.Stats, err
|
2018-10-08 23:15:54 +01:00
|
|
|
}
|