Use generated locking database implementation (#947)

This commit is contained in:
Egon Elbre 2019-01-02 19:53:27 +02:00 committed by GitHub
parent 249244536a
commit 0ca03b41e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 727 additions and 317 deletions

6
go.mod
View File

@ -108,11 +108,13 @@ require (
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941
golang.org/x/net v0.0.0-20181003013248-f5e5bdd77824
golang.org/x/net v0.0.0-20181106065722-10aee1819953
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
golang.org/x/sys v0.0.0-20181213081344-73d4af5aa059
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
google.golang.org/grpc v1.15.0
golang.org/x/tools v0.0.0-20181221235234-d00ac6d27372
google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f // indirect
google.golang.org/grpc v1.16.0
gopkg.in/Shopify/sarama.v1 v1.18.0 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.25 // indirect
gopkg.in/olivere/elastic.v5 v5.0.76 // indirect

8
go.sum
View File

@ -346,6 +346,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181003013248-f5e5bdd77824 h1:MkjFNbaZJyH98M67Q3umtwZ+EdVdrNJLqSwZp5vcv60=
golang.org/x/net v0.0.0-20181003013248-f5e5bdd77824/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953 h1:LuZIitY8waaxUfNIdtajyE/YzA/zyf0YxXG27VpLrkg=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
@ -366,6 +368,8 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5P
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180911133044-677d2ff680c1 h1:dzEuQYa6+a3gROnSlgly5ERUm4SZKJt+dh+4iSbO+bI=
golang.org/x/tools v0.0.0-20180911133044-677d2ff680c1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221235234-d00ac6d27372 h1:zWPUEY/PjVHT+zO3L8OfkjrtIjf55joTxn/RQP/AjOI=
golang.org/x/tools v0.0.0-20181221235234-d00ac6d27372/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/api v0.0.0-20180818000503-e21acd801f91/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20180826000528-7954115fcf34/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@ -375,9 +379,13 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180912233945-5a2fd4cab2d6 h1:YN6g8chEdBTmaERxJzbJ6WKLrW3+Bf6rznOBkWNSQP0=
google.golang.org/genproto v0.0.0-20180912233945-5a2fd4cab2d6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f h1:eT3B0O2ghdSPzjAOznr3oOLyN1HFeYUncYl7FRwg4VI=
google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.15.0 h1:Az/KuahOM4NAidTEuJCv/RonAA7rYsTPkqXVjr+8OOw=
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
gopkg.in/Shopify/sarama.v1 v1.18.0 h1:f9aTXuIEFEjVvLG9p+kMSk01dMfFumHsySRk1okTdqU=
gopkg.in/Shopify/sarama.v1 v1.18.0/go.mod h1:AxnvoaevB2nBjNK17cG61A3LleFcWFwVBHBt+cot4Oc=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=

View File

@ -10,13 +10,12 @@ import (
"storj.io/storj/pkg/storj"
)
//DB is an interface for interacting with accounting stuff
// DB stores information about bandwidth usage
type DB interface {
// LastRawTime records the greatest last tallied time
// LastRawTime records the latest last tallied time.
LastRawTime(ctx context.Context, timestampType string) (time.Time, bool, error)
// SaveBWRaw records raw sums of bw agreement values to the database
// and updates the LastRawTime
// SaveBWRaw records raw sums of agreement values to the database and updates the LastRawTime.
SaveBWRaw(ctx context.Context, latestBwa time.Time, bwTotals map[string]int64) error
// SaveAtRestRaw records raw tallies of at rest data to the database
// SaveAtRestRaw records raw tallies of at-rest-data.
SaveAtRestRaw(ctx context.Context, latestTally time.Time, nodeData map[storj.NodeID]int64) error
}

View File

@ -18,13 +18,13 @@ import (
"storj.io/storj/pkg/peertls"
)
// DB interface for database operations
// DB stores bandwidth agreements.
type DB interface {
// CreateAgreement creates bandwidth agreement in database
// CreateAgreement adds a new bandwidth agreement.
CreateAgreement(context.Context, Agreement) error
// GetAgreements gets all bandwidth agreements
// GetAgreements gets all bandwidth agreements.
GetAgreements(context.Context) ([]Agreement, error)
// GetAgreementsSince gets all bandwidth agreements since specific time
// GetAgreementsSince gets all bandwidth agreements since specific time.
GetAgreementsSince(context.Context, time.Time) ([]Agreement, error)
}

View File

@ -7,17 +7,17 @@ import (
"context"
)
// DB interface for database operations
// DB stores information about repairs that have failed.
type DB interface {
// IncrementRepairAttempts increments the repair attempt
// IncrementRepairAttempts increments the repair attempts.
IncrementRepairAttempts(ctx context.Context, segmentInfo *RemoteSegmentInfo) error
// Get a irreparable's segment info from the db
// Get returns irreparable segment info based on segmentPath.
Get(ctx context.Context, segmentPath []byte) (*RemoteSegmentInfo, error)
// Delete a irreparable's segment info from the db
// Delete removes irreparable segment info based on segmentPath.
Delete(ctx context.Context, segmentPath []byte) error
}
// RemoteSegmentInfo is info about a single entry stored in the irreparable
// RemoteSegmentInfo is information about failed repairs.
type RemoteSegmentInfo struct {
EncryptedSegmentPath []byte
EncryptedSegmentDetail []byte //contains marshaled info of pb.Pointer

View File

@ -13,10 +13,13 @@ import (
"storj.io/storj/storage"
)
// RepairQueue is the interface for the data repair queue
// RepairQueue implements queueing for segments that need repairing.
type RepairQueue interface {
// Enqueue adds an injured segment.
Enqueue(ctx context.Context, qi *pb.InjuredSegment) error
// Dequeue removes an injured segment.
Dequeue(ctx context.Context) (pb.InjuredSegment, error)
// Peekqueue lists limit amount of injured segments.
Peekqueue(ctx context.Context, limit int) ([]pb.InjuredSegment, error)
}

View File

@ -9,41 +9,34 @@ import (
"storj.io/storj/pkg/storj"
)
// DB interface for database operations
// DB stores node statistics
type DB interface {
// Create a db entry for the provided storagenode
Create(ctx context.Context, nodeID storj.NodeID, startingStats *NodeStats) (stats *NodeStats, err error)
// Get a storagenode's stats from the db
// Create adds a new stats entry for node.
Create(ctx context.Context, nodeID storj.NodeID, initial *NodeStats) (stats *NodeStats, err error)
// Get returns node stats.
Get(ctx context.Context, nodeID storj.NodeID) (stats *NodeStats, err error)
// FindInvalidNodes finds a subset of storagenodes that have stats below provided reputation requirements
FindInvalidNodes(ctx context.Context, nodeIDs storj.NodeIDList, maxStats *NodeStats) (invalidIDs storj.NodeIDList, err error)
// Update all parts of single storagenode's stats in the db
Update(ctx context.Context, updateReq *UpdateRequest) (stats *NodeStats, err error)
// UpdateUptime updates a single storagenode's uptime stats in the db
// FindInvalidNodes finds a subset of storagenodes that have stats below provided reputation requirements.
FindInvalidNodes(ctx context.Context, nodeIDs storj.NodeIDList, maxStats *NodeStats) (invalid storj.NodeIDList, err error)
// Update all parts of single storagenode's stats.
Update(ctx context.Context, request *UpdateRequest) (stats *NodeStats, err error)
// UpdateUptime updates a single storagenode's uptime stats.
UpdateUptime(ctx context.Context, nodeID storj.NodeID, isUp bool) (stats *NodeStats, err error)
// UpdateAuditSuccess updates a single storagenode's audit stats in the db
// UpdateAuditSuccess updates a single storagenode's audit stats.
UpdateAuditSuccess(ctx context.Context, nodeID storj.NodeID, auditSuccess bool) (stats *NodeStats, err error)
// UpdateBatch for updating multiple storage nodes' stats in the db
UpdateBatch(ctx context.Context, updateReqList []*UpdateRequest) (statsList []*NodeStats, failedUpdateReqs []*UpdateRequest, err error)
// CreateEntryIfNotExists creates a statdb node entry and saves to statdb if it didn't already exist
// UpdateBatch for updating multiple storage nodes' stats.
UpdateBatch(ctx context.Context, requests []*UpdateRequest) (statslist []*NodeStats, failed []*UpdateRequest, err error)
// CreateEntryIfNotExists creates a node stats entry if it didn't already exist.
CreateEntryIfNotExists(ctx context.Context, nodeID storj.NodeID) (stats *NodeStats, err error)
}
// UpdateRequest is a statdb update request message
// UpdateRequest is used to update a node status.
type UpdateRequest struct {
NodeID storj.NodeID
AuditSuccess bool
IsUp bool
}
// NodeStats is a statdb node stats message
// NodeStats contains statistics abot a node.
type NodeStats struct {
NodeID storj.NodeID
AuditSuccessRatio float64

View File

@ -14,14 +14,21 @@ import (
// DB is the master database for the satellite
type DB interface {
BandwidthAgreement() bwagreement.DB
// PointerDB() pointerdb.DB
StatDB() statdb.DB
OverlayCache() storage.KeyValueStore
RepairQueue() queue.RepairQueue
Accounting() accounting.DB
Irreparable() irreparable.DB
// CreateTables initializes the database
CreateTables() error
// Close closes the database
Close() error
// BandwidthAgreement returns database for storing bandwidth agreements
BandwidthAgreement() bwagreement.DB
// StatDB returns database for storing node statistics
StatDB() statdb.DB
// OverlayCache returns database for caching overlay information
OverlayCache() storage.KeyValueStore
// Accounting returns database for storing information about data use
Accounting() accounting.DB
// RepairQueue returns queue for segments that need repairing
RepairQueue() queue.RepairQueue
// Irreparable returns database for failed repairs
Irreparable() irreparable.DB
}

View File

@ -23,6 +23,8 @@ var (
Error = errs.Class("satellitedb")
)
//go:generate go run lockedgen/main.go -o locked.go
// DB contains access to different database tables
type DB struct {
db *dbx.DB
@ -43,7 +45,7 @@ func New(databaseURL string) (satellite.DB, error) {
core := &DB{db: db}
if driver == "sqlite3" {
return NewMutex(core), nil
return newLocked(core), nil
}
return core, nil
}

View File

@ -196,5 +196,4 @@ read first (
read limitoffset (
select injuredsegment
)
delete injuredsegment ( where injuredsegment.id = ? )

View File

@ -0,0 +1,321 @@
// Code generated by lockedgen using 'go generate'. DO NOT EDIT.
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
"context"
"sync"
"time"
"storj.io/storj/pkg/accounting"
"storj.io/storj/pkg/bwagreement"
"storj.io/storj/pkg/datarepair/irreparable"
"storj.io/storj/pkg/datarepair/queue"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/statdb"
"storj.io/storj/pkg/storj"
"storj.io/storj/satellite"
"storj.io/storj/storage"
)
// locked implements a locking wrapper around satellite.DB.
type locked struct {
sync.Locker
db satellite.DB
}
// newLocked returns database wrapped with locker.
func newLocked(db satellite.DB) satellite.DB {
return &locked{&sync.Mutex{}, db}
}
// Accounting returns database for storing information about data use
func (m *locked) Accounting() accounting.DB {
m.Lock()
defer m.Unlock()
return &lockedAccounting{m.Locker, m.db.Accounting()}
}
// BandwidthAgreement returns database for storing bandwidth agreements
func (m *locked) BandwidthAgreement() bwagreement.DB {
m.Lock()
defer m.Unlock()
return &lockedBandwidthAgreement{m.Locker, m.db.BandwidthAgreement()}
}
// Close closes the database
func (m *locked) Close() error {
m.Lock()
defer m.Unlock()
return m.db.Close()
}
// CreateTables initializes the database
func (m *locked) CreateTables() error {
m.Lock()
defer m.Unlock()
return m.db.CreateTables()
}
// Irreparable returns database for failed repairs
func (m *locked) Irreparable() irreparable.DB {
m.Lock()
defer m.Unlock()
return &lockedIrreparable{m.Locker, m.db.Irreparable()}
}
// OverlayCache returns database for caching overlay information
func (m *locked) OverlayCache() storage.KeyValueStore {
m.Lock()
defer m.Unlock()
return &lockedOverlayCache{m.Locker, m.db.OverlayCache()}
}
// RepairQueue returns queue for segments that need repairing
func (m *locked) RepairQueue() queue.RepairQueue {
m.Lock()
defer m.Unlock()
return &lockedRepairQueue{m.Locker, m.db.RepairQueue()}
}
// StatDB returns database for storing node statistics
func (m *locked) StatDB() statdb.DB {
m.Lock()
defer m.Unlock()
return &lockedStatDB{m.Locker, m.db.StatDB()}
}
// lockedAccounting implements locking wrapper for accounting.DB
type lockedAccounting struct {
sync.Locker
db accounting.DB
}
// LastRawTime records the latest last tallied time.
func (m *lockedAccounting) LastRawTime(ctx context.Context, timestampType string) (time.Time, bool, error) {
m.Lock()
defer m.Unlock()
return m.db.LastRawTime(ctx, timestampType)
}
// SaveAtRestRaw records raw tallies of at-rest-data.
func (m *lockedAccounting) SaveAtRestRaw(ctx context.Context, latestTally time.Time, nodeData map[storj.NodeID]int64) error {
m.Lock()
defer m.Unlock()
return m.db.SaveAtRestRaw(ctx, latestTally, nodeData)
}
// SaveBWRaw records raw sums of agreement values to the database and updates the LastRawTime.
func (m *lockedAccounting) SaveBWRaw(ctx context.Context, latestBwa time.Time, bwTotals map[string]int64) error {
m.Lock()
defer m.Unlock()
return m.db.SaveBWRaw(ctx, latestBwa, bwTotals)
}
// lockedBandwidthAgreement implements locking wrapper for bwagreement.DB
type lockedBandwidthAgreement struct {
sync.Locker
db bwagreement.DB
}
// CreateAgreement adds a new bandwidth agreement.
func (m *lockedBandwidthAgreement) CreateAgreement(ctx context.Context, a1 bwagreement.Agreement) error {
m.Lock()
defer m.Unlock()
return m.db.CreateAgreement(ctx, a1)
}
// GetAgreements gets all bandwidth agreements.
func (m *lockedBandwidthAgreement) GetAgreements(ctx context.Context) ([]bwagreement.Agreement, error) {
m.Lock()
defer m.Unlock()
return m.db.GetAgreements(ctx)
}
// GetAgreementsSince gets all bandwidth agreements since specific time.
func (m *lockedBandwidthAgreement) GetAgreementsSince(ctx context.Context, a1 time.Time) ([]bwagreement.Agreement, error) {
m.Lock()
defer m.Unlock()
return m.db.GetAgreementsSince(ctx, a1)
}
// lockedIrreparable implements locking wrapper for irreparable.DB
type lockedIrreparable struct {
sync.Locker
db irreparable.DB
}
// Delete removes irreparable segment info based on segmentPath.
func (m *lockedIrreparable) Delete(ctx context.Context, segmentPath []byte) error {
m.Lock()
defer m.Unlock()
return m.db.Delete(ctx, segmentPath)
}
// Get returns irreparable segment info based on segmentPath.
func (m *lockedIrreparable) Get(ctx context.Context, segmentPath []byte) (*irreparable.RemoteSegmentInfo, error) {
m.Lock()
defer m.Unlock()
return m.db.Get(ctx, segmentPath)
}
// IncrementRepairAttempts increments the repair attempts.
func (m *lockedIrreparable) IncrementRepairAttempts(ctx context.Context, segmentInfo *irreparable.RemoteSegmentInfo) error {
m.Lock()
defer m.Unlock()
return m.db.IncrementRepairAttempts(ctx, segmentInfo)
}
// lockedOverlayCache implements locking wrapper for storage.KeyValueStore
type lockedOverlayCache struct {
sync.Locker
db storage.KeyValueStore
}
// Close closes the store
func (m *lockedOverlayCache) Close() error {
m.Lock()
defer m.Unlock()
return m.db.Close()
}
// Delete deletes key and the value
func (m *lockedOverlayCache) Delete(a0 storage.Key) error {
m.Lock()
defer m.Unlock()
return m.db.Delete(a0)
}
// Get gets a value to store
func (m *lockedOverlayCache) Get(a0 storage.Key) (storage.Value, error) {
m.Lock()
defer m.Unlock()
return m.db.Get(a0)
}
// GetAll gets all values from the store
func (m *lockedOverlayCache) GetAll(a0 storage.Keys) (storage.Values, error) {
m.Lock()
defer m.Unlock()
return m.db.GetAll(a0)
}
// Iterate iterates over items based on opts
func (m *lockedOverlayCache) Iterate(opts storage.IterateOptions, fn func(storage.Iterator) error) error {
m.Lock()
defer m.Unlock()
return m.db.Iterate(opts, fn)
}
// List lists all keys starting from start and upto limit items
func (m *lockedOverlayCache) List(start storage.Key, limit int) (storage.Keys, error) {
m.Lock()
defer m.Unlock()
return m.db.List(start, limit)
}
// Put adds a value to store
func (m *lockedOverlayCache) Put(a0 storage.Key, a1 storage.Value) error {
m.Lock()
defer m.Unlock()
return m.db.Put(a0, a1)
}
// ReverseList lists all keys in revers order
func (m *lockedOverlayCache) ReverseList(a0 storage.Key, a1 int) (storage.Keys, error) {
m.Lock()
defer m.Unlock()
return m.db.ReverseList(a0, a1)
}
// lockedRepairQueue implements locking wrapper for queue.RepairQueue
type lockedRepairQueue struct {
sync.Locker
db queue.RepairQueue
}
// Dequeue removes an injured segment.
func (m *lockedRepairQueue) Dequeue(ctx context.Context) (pb.InjuredSegment, error) {
m.Lock()
defer m.Unlock()
return m.db.Dequeue(ctx)
}
// Enqueue adds an injured segment.
func (m *lockedRepairQueue) Enqueue(ctx context.Context, qi *pb.InjuredSegment) error {
m.Lock()
defer m.Unlock()
return m.db.Enqueue(ctx, qi)
}
// Peekqueue lists limit amount of injured segments.
func (m *lockedRepairQueue) Peekqueue(ctx context.Context, limit int) ([]pb.InjuredSegment, error) {
m.Lock()
defer m.Unlock()
return m.db.Peekqueue(ctx, limit)
}
// lockedStatDB implements locking wrapper for statdb.DB
type lockedStatDB struct {
sync.Locker
db statdb.DB
}
// Create adds a new stats entry for node.
func (m *lockedStatDB) Create(ctx context.Context, nodeID storj.NodeID, initial *statdb.NodeStats) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.Create(ctx, nodeID, initial)
}
// CreateEntryIfNotExists creates a node stats entry if it didn't already exist.
func (m *lockedStatDB) CreateEntryIfNotExists(ctx context.Context, nodeID storj.NodeID) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.CreateEntryIfNotExists(ctx, nodeID)
}
// FindInvalidNodes finds a subset of storagenodes that have stats below provided reputation requirements.
func (m *lockedStatDB) FindInvalidNodes(ctx context.Context, nodeIDs storj.NodeIDList, maxStats *statdb.NodeStats) (invalid storj.NodeIDList, err error) {
m.Lock()
defer m.Unlock()
return m.db.FindInvalidNodes(ctx, nodeIDs, maxStats)
}
// Get returns node stats.
func (m *lockedStatDB) Get(ctx context.Context, nodeID storj.NodeID) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.Get(ctx, nodeID)
}
// Update all parts of single storagenode's stats.
func (m *lockedStatDB) Update(ctx context.Context, request *statdb.UpdateRequest) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.Update(ctx, request)
}
// UpdateAuditSuccess updates a single storagenode's audit stats.
func (m *lockedStatDB) UpdateAuditSuccess(ctx context.Context, nodeID storj.NodeID, auditSuccess bool) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.UpdateAuditSuccess(ctx, nodeID, auditSuccess)
}
// UpdateBatch for updating multiple storagenodes stats.
func (m *lockedStatDB) UpdateBatch(ctx context.Context, requests []*statdb.UpdateRequest) (statslist []*statdb.NodeStats, failed []*statdb.UpdateRequest, err error) {
m.Lock()
defer m.Unlock()
return m.db.UpdateBatch(ctx, requests)
}
// UpdateUptime updates a single storagenode's uptime stats.
func (m *lockedStatDB) UpdateUptime(ctx context.Context, nodeID storj.NodeID, isUp bool) (stats *statdb.NodeStats, err error) {
m.Lock()
defer m.Unlock()
return m.db.UpdateUptime(ctx, nodeID, isUp)
}

View File

@ -0,0 +1,343 @@
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/token"
"go/types"
"io/ioutil"
"sort"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/imports"
)
func main() {
var outputPath string
flag.StringVar(&outputPath, "o", "", "output file name")
flag.Parse()
var code Code
code.Imports = map[string]bool{}
code.Ignore = map[string]bool{
"error": true,
}
code.Config = &packages.Config{
Mode: packages.LoadAllSyntax,
}
code.Package = "storj.io/storj/satellite"
var err error
code.Roots, err = packages.Load(code.Config, code.Package)
if err != nil {
panic(err)
}
code.PrintLocked()
code.PrintPreamble()
unformatted := code.Bytes()
imports.LocalPrefix = "storj.io"
formatted, err := imports.Process(outputPath, unformatted, nil)
if err != nil {
fmt.Println(string(unformatted))
panic(err)
}
if outputPath == "" {
fmt.Println(string(formatted))
return
}
err = ioutil.WriteFile(outputPath, formatted, 0644)
if err != nil {
panic(err)
}
}
// Methods is the common interface for types having methods.
type Methods interface {
Method(i int) *types.Func
NumMethods() int
}
// Code is the information for generating the code.
type Code struct {
Config *packages.Config
Package string
Roots []*packages.Package
Imports map[string]bool
Ignore map[string]bool
Preamble bytes.Buffer
Source bytes.Buffer
}
// Bytes returns all code merged together
func (code *Code) Bytes() []byte {
var all bytes.Buffer
all.Write(code.Preamble.Bytes())
all.Write(code.Source.Bytes())
return all.Bytes()
}
// PrintPreamble creates package header and imports.
func (code *Code) PrintPreamble() {
w := &code.Preamble
fmt.Fprintf(w, "// Code generated by lockedgen using 'go generate'. DO NOT EDIT.\n\n")
fmt.Fprintf(w, "// Copyright (C) 2018 Storj Labs, Inc.\n")
fmt.Fprintf(w, "// See LICENSE for copying information.\n\n")
fmt.Fprintf(w, "package satellitedb\n\n")
fmt.Fprintf(w, "import (\n")
var imports []string
for imp := range code.Imports {
imports = append(imports, imp)
}
sort.Strings(imports)
for _, imp := range imports {
fmt.Fprintf(w, " %q\n", imp)
}
fmt.Fprintf(w, ")\n\n")
}
// PrintLocked writes locked wrapper and methods.
func (code *Code) PrintLocked() {
code.Imports["sync"] = true
code.Imports["storj.io/statellite"] = true
code.Printf("// locked implements a locking wrapper around satellite.DB.\n")
code.Printf("type locked struct {\n")
code.Printf(" sync.Locker\n")
code.Printf(" db satellite.DB\n")
code.Printf("}\n\n")
code.Printf("// newLocked returns database wrapped with locker.\n")
code.Printf("func newLocked(db satellite.DB) satellite.DB {\n")
code.Printf(" return &locked{&sync.Mutex{}, db}\n")
code.Printf("}\n\n")
// find the satellite.DB type info
dbObject := code.Roots[0].Types.Scope().Lookup("DB")
methods := dbObject.Type().Underlying().(Methods)
for i := 0; i < methods.NumMethods(); i++ {
code.PrintLockedFunc("locked", methods.Method(i), true)
}
for i := 0; i < methods.NumMethods(); i++ {
if !code.NeedsWrapper(methods.Method(i)) {
continue
}
code.PrintWrapper(methods.Method(i))
}
}
// Printf writes formatted text to source.
func (code *Code) Printf(format string, a ...interface{}) {
fmt.Fprintf(&code.Source, format, a...)
}
// PrintSignature prints method signature.
func (code *Code) PrintSignature(sig *types.Signature) {
code.PrintSignatureTuple(sig.Params(), true)
if sig.Results().Len() > 0 {
code.Printf(" ")
code.PrintSignatureTuple(sig.Results(), false)
}
}
// PrintSignatureTuple prints method tuple, params or results.
func (code *Code) PrintSignatureTuple(tuple *types.Tuple, needsNames bool) {
code.Printf("(")
defer code.Printf(")")
for i := 0; i < tuple.Len(); i++ {
if i > 0 {
code.Printf(", ")
}
param := tuple.At(i)
if code.PrintName(tuple.At(i), i, needsNames) {
code.Printf(" ")
}
code.PrintType(param.Type())
}
}
// PrintCall prints a call using the specified signature.
func (code *Code) PrintCall(sig *types.Signature) {
code.Printf("(")
defer code.Printf(")")
params := sig.Params()
for i := 0; i < params.Len(); i++ {
if i != 0 {
code.Printf(", ")
}
code.PrintName(params.At(i), i, true)
}
}
// PrintName prints an appropriate name from signature tuple.
func (code *Code) PrintName(v *types.Var, index int, needsNames bool) bool {
name := v.Name()
if needsNames && name == "" {
if v.Type().String() == "context.Context" {
code.Printf("ctx")
return true
}
code.Printf("a%d", index)
return true
}
code.Printf("%s", name)
return name != ""
}
// PrintType prints short form of type t.
func (code *Code) PrintType(t types.Type) {
types.WriteType(&code.Source, t, (*types.Package).Name)
}
func typeName(typ types.Type) string {
var body bytes.Buffer
types.WriteType(&body, typ, (*types.Package).Name)
return body.String()
}
// IncludeImports imports all types referenced in the signature.
func (code *Code) IncludeImports(sig *types.Signature) {
var tmp bytes.Buffer
types.WriteSignature(&tmp, sig, func(p *types.Package) string {
code.Imports[p.Path()] = true
return p.Name()
})
}
// NeedsWrapper checks whether method result needs a wrapper type.
func (code *Code) NeedsWrapper(method *types.Func) bool {
sig := method.Type().Underlying().(*types.Signature)
return sig.Results().Len() == 1 && !code.Ignore[sig.Results().At(0).Type().String()]
}
// WrapperTypeName returns an appropariate name for the wrapper type.
func (code *Code) WrapperTypeName(method *types.Func) string {
return "locked" + method.Name()
}
// PrintLockedFunc prints a method with locking and defers the actual logic to method.
func (code *Code) PrintLockedFunc(receiverType string, method *types.Func, allowNesting bool) {
sig := method.Type().Underlying().(*types.Signature)
code.IncludeImports(sig)
doc := code.MethodDoc(method)
if doc != "" {
code.Printf("// %s", code.MethodDoc(method))
}
code.Printf("func (m *%s) %s", receiverType, method.Name())
code.PrintSignature(sig)
code.Printf(" {\n")
defer code.Printf("}\n\n")
code.Printf(" m.Lock(); defer m.Unlock()\n")
if code.NeedsWrapper(method) {
code.Printf(" return &%s{m.Locker, ", code.WrapperTypeName(method))
code.Printf("m.db.%s", method.Name())
code.PrintCall(sig)
code.Printf("}\n")
} else {
code.Printf(" return m.db.%s", method.Name())
code.PrintCall(sig)
code.Printf("\n")
}
}
// PrintWrapper prints wrapper for the result type of method.
func (code *Code) PrintWrapper(method *types.Func) {
sig := method.Type().Underlying().(*types.Signature)
results := sig.Results()
result := results.At(0).Type()
receiverType := code.WrapperTypeName(method)
code.Printf("// %s implements locking wrapper for %s\n", receiverType, typeName(result))
code.Printf("type %s struct {\n", receiverType)
code.Printf(" sync.Locker\n")
code.Printf(" db %s\n", typeName(result))
code.Printf("}\n\n")
methods := result.Underlying().(Methods)
for i := 0; i < methods.NumMethods(); i++ {
code.PrintLockedFunc(receiverType, methods.Method(i), false)
}
}
// MethodDoc finds documentation for the specified method.
func (code *Code) MethodDoc(method *types.Func) string {
file := code.FindASTFile(method.Pos())
if file == nil {
return ""
}
path, exact := astutil.PathEnclosingInterval(file, method.Pos(), method.Pos())
if !exact {
return ""
}
for _, p := range path {
switch decl := p.(type) {
case *ast.Field:
return decl.Doc.Text()
case *ast.GenDecl:
return decl.Doc.Text()
case *ast.FuncDecl:
return decl.Doc.Text()
}
}
return ""
}
// FindASTFile finds the *ast.File at the specified position.
func (code *Code) FindASTFile(pos token.Pos) *ast.File {
seen := map[*packages.Package]bool{}
// find searches pos recursively from p and its dependencies.
var find func(p *packages.Package) *ast.File
find = func(p *packages.Package) *ast.File {
if seen[p] {
return nil
}
seen[p] = true
for _, file := range p.Syntax {
if file.Pos() <= pos && pos <= file.End() {
return file
}
}
for _, dep := range p.Imports {
if file := find(dep); file != nil {
return file
}
}
return nil
}
for _, root := range code.Roots {
if file := find(root); file != nil {
return file
}
}
return nil
}

View File

@ -1,267 +0,0 @@
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
"context"
"errors"
"sync"
"time"
"storj.io/storj/pkg/accounting"
"storj.io/storj/pkg/bwagreement"
"storj.io/storj/pkg/datarepair/irreparable"
"storj.io/storj/pkg/datarepair/queue"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/statdb"
"storj.io/storj/pkg/storj"
"storj.io/storj/storage"
)
// Mutex wraps DB in a mutex for non-concurrent databases
type Mutex struct {
mu sync.Mutex
db *DB
}
// NewMutex returns a mutex around DB
func NewMutex(db *DB) *Mutex {
return &Mutex{db: db}
}
func (db *Mutex) locked() func() {
db.mu.Lock()
return db.mu.Unlock
}
// BandwidthAgreement is a getter for bandwidth agreement repository
func (db *Mutex) BandwidthAgreement() bwagreement.DB {
return &muBandwidthAgreement{mu: db, bandwidth: db.db.BandwidthAgreement()}
}
// // PointerDB is a getter for PointerDB repository
// func (db *Mutex) PointerDB() pointerdb.DB {
// return &pointerDB{db: db.db}
// }
// StatDB is a getter for StatDB repository
func (db *Mutex) StatDB() statdb.DB {
return &muStatDB{mu: db, statdb: db.db.StatDB()}
}
// OverlayCache is a getter for overlay cache repository
func (db *Mutex) OverlayCache() storage.KeyValueStore {
return &muOverlayCache{mu: db, overlay: db.db.OverlayCache()}
}
// RepairQueue is a getter for RepairQueue repository
func (db *Mutex) RepairQueue() queue.RepairQueue {
return &muRepairQueue{mu: db, repair: db.db.RepairQueue()}
}
// Accounting returns database for tracking bandwidth agreements over time
func (db *Mutex) Accounting() accounting.DB {
return &muAccounting{mu: db, accounting: db.db.Accounting()}
}
// Irreparable returns database for storing segments that failed repair
func (db *Mutex) Irreparable() irreparable.DB {
return &muIrreparable{mu: db, irreparable: db.db.Irreparable()}
}
// CreateTables is a method for creating all tables for database
func (db *Mutex) CreateTables() error {
return db.db.CreateTables()
}
// Close is used to close db connection
func (db *Mutex) Close() error {
return db.db.Close()
}
type muBandwidthAgreement struct {
mu *Mutex
bandwidth bwagreement.DB
}
func (db *muBandwidthAgreement) CreateAgreement(ctx context.Context, agreement bwagreement.Agreement) error {
defer db.mu.locked()()
return db.bandwidth.CreateAgreement(ctx, agreement)
}
func (db *muBandwidthAgreement) GetAgreements(ctx context.Context) ([]bwagreement.Agreement, error) {
defer db.mu.locked()()
return db.bandwidth.GetAgreements(ctx)
}
func (db *muBandwidthAgreement) GetAgreementsSince(ctx context.Context, since time.Time) ([]bwagreement.Agreement, error) {
defer db.mu.locked()()
return db.bandwidth.GetAgreementsSince(ctx, since)
}
// muStatDB implements mutex around statdb.DB
type muStatDB struct {
mu *Mutex
statdb statdb.DB
}
// Create a db entry for the provided storagenode
func (db *muStatDB) Create(ctx context.Context, nodeID storj.NodeID, startingStats *statdb.NodeStats) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.Create(ctx, nodeID, startingStats)
}
// Get a storagenode's stats from the db
func (db *muStatDB) Get(ctx context.Context, nodeID storj.NodeID) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.Get(ctx, nodeID)
}
// FindInvalidNodes finds a subset of storagenodes that have stats below provided reputation requirements
func (db *muStatDB) FindInvalidNodes(ctx context.Context, nodeIDs storj.NodeIDList, maxStats *statdb.NodeStats) (invalidIDs storj.NodeIDList, err error) {
defer db.mu.locked()()
return db.statdb.FindInvalidNodes(ctx, nodeIDs, maxStats)
}
// Update all parts of single storagenode's stats in the db
func (db *muStatDB) Update(ctx context.Context, updateReq *statdb.UpdateRequest) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.Update(ctx, updateReq)
}
// UpdateUptime updates a single storagenode's uptime stats in the db
func (db *muStatDB) UpdateUptime(ctx context.Context, nodeID storj.NodeID, isUp bool) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.UpdateUptime(ctx, nodeID, isUp)
}
// UpdateAuditSuccess updates a single storagenode's audit stats in the db
func (db *muStatDB) UpdateAuditSuccess(ctx context.Context, nodeID storj.NodeID, auditSuccess bool) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.UpdateAuditSuccess(ctx, nodeID, auditSuccess)
}
// UpdateBatch for updating multiple storage nodes' stats in the db
func (db *muStatDB) UpdateBatch(ctx context.Context, updateReqList []*statdb.UpdateRequest) (statsList []*statdb.NodeStats, failedUpdateReqs []*statdb.UpdateRequest, err error) {
defer db.mu.locked()()
return db.statdb.UpdateBatch(ctx, updateReqList)
}
// CreateEntryIfNotExists creates a statdb node entry and saves to statdb if it didn't already exist
func (db *muStatDB) CreateEntryIfNotExists(ctx context.Context, nodeID storj.NodeID) (stats *statdb.NodeStats, err error) {
defer db.mu.locked()()
return db.statdb.CreateEntryIfNotExists(ctx, nodeID)
}
// muOverlayCache implements a mutex around overlay cache
type muOverlayCache struct {
mu *Mutex
overlay storage.KeyValueStore
}
// Put adds a value to store
func (db *muOverlayCache) Put(key storage.Key, value storage.Value) error {
defer db.mu.locked()()
return db.overlay.Put(key, value)
}
// Get gets a value to store
func (db *muOverlayCache) Get(key storage.Key) (storage.Value, error) {
defer db.mu.locked()()
return db.overlay.Get(key)
}
// GetAll gets all values from the store
func (db *muOverlayCache) GetAll(keys storage.Keys) (storage.Values, error) {
defer db.mu.locked()()
return db.overlay.GetAll(keys)
}
// Delete deletes key and the value
func (db *muOverlayCache) Delete(key storage.Key) error {
defer db.mu.locked()()
return db.overlay.Delete(key)
}
// List lists all keys starting from start and upto limit items
func (db *muOverlayCache) List(start storage.Key, limit int) (keys storage.Keys, err error) {
defer db.mu.locked()()
return db.overlay.List(start, limit)
}
// ReverseList lists all keys in revers order
func (db *muOverlayCache) ReverseList(start storage.Key, limit int) (storage.Keys, error) {
defer db.mu.locked()()
return db.overlay.ReverseList(start, limit)
}
// Iterate iterates over items based on opts
func (db *muOverlayCache) Iterate(opts storage.IterateOptions, fn func(storage.Iterator) error) error {
return errors.New("not implemented")
}
// Close closes the store
func (db *muOverlayCache) Close() error {
defer db.mu.locked()()
return db.overlay.Close()
}
// muRepairQueue implements mutex around repair queue
type muRepairQueue struct {
mu *Mutex
repair queue.RepairQueue
}
func (db *muRepairQueue) Enqueue(ctx context.Context, seg *pb.InjuredSegment) error {
defer db.mu.locked()()
return db.repair.Enqueue(ctx, seg)
}
func (db *muRepairQueue) Dequeue(ctx context.Context) (pb.InjuredSegment, error) {
defer db.mu.locked()()
return db.repair.Dequeue(ctx)
}
func (db *muRepairQueue) Peekqueue(ctx context.Context, limit int) ([]pb.InjuredSegment, error) {
defer db.mu.locked()()
return db.repair.Peekqueue(ctx, limit)
}
type muAccounting struct {
mu *Mutex
accounting accounting.DB
}
func (db *muAccounting) LastRawTime(ctx context.Context, timestampType string) (time.Time, bool, error) {
defer db.mu.locked()()
return db.accounting.LastRawTime(ctx, timestampType)
}
func (db *muAccounting) SaveBWRaw(ctx context.Context, latestBwa time.Time, bwTotals map[string]int64) (err error) {
defer db.mu.locked()()
return db.accounting.SaveBWRaw(ctx, latestBwa, bwTotals)
}
func (db *muAccounting) SaveAtRestRaw(ctx context.Context, latestTally time.Time, nodeData map[storj.NodeID]int64) error {
defer db.mu.locked()()
return db.accounting.SaveAtRestRaw(ctx, latestTally, nodeData)
}
type muIrreparable struct {
mu *Mutex
irreparable irreparable.DB
}
func (db *muIrreparable) IncrementRepairAttempts(ctx context.Context, segmentInfo *irreparable.RemoteSegmentInfo) (err error) {
defer db.mu.locked()()
return db.irreparable.IncrementRepairAttempts(ctx, segmentInfo)
}
func (db *muIrreparable) Get(ctx context.Context, segmentPath []byte) (resp *irreparable.RemoteSegmentInfo, err error) {
defer db.mu.locked()()
return db.irreparable.Get(ctx, segmentPath)
}
func (db *muIrreparable) Delete(ctx context.Context, segmentPath []byte) (err error) {
defer db.mu.locked()()
return db.irreparable.Delete(ctx, segmentPath)
}

View File

@ -50,7 +50,7 @@ type ListItem struct {
IsPrefix bool
}
// KeyValueStore is an interface describing key/value stores like redis and boltdb
// KeyValueStore describes key/value stores like redis and boltdb
type KeyValueStore interface {
// Put adds a value to store
Put(Key, Value) error