storj/pkg/audit/cursor.go
Kaloyan Raev 99640225fd
Refactor Path type (#522)
The old paths.Path type is now replaced with the new storj.Path.

storj.Path is simply an alias to the built-in string type. As such it can be used just as any string, which simplifies a lot working with paths. No more conversions paths.New and path.String().

As an alias storj.Path does not define any methods. However, any functions applying to strings (like those from the strings package) gracefully apply to storj.Path too. In addition we have a few more functions defined:

    storj.SplitPath
    storj.JoinPaths
    encryption.EncryptPath
    encryption.DecryptPath
    encryption.DerivePathKey
    encryption.DeriveContentKey

All code in master is migrated to the new storj.Path type.

The Path example is also updated and is good for reference: /pkg/encryption/examples_test.go

This PR also resolve a nonce misuse issue in path encryption: https://storjlabs.atlassian.net/browse/V3-545
2018-10-25 23:28:16 +03:00

123 lines
2.9 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package audit
import (
"context"
"crypto/rand"
"math/big"
"sync"
"github.com/vivint/infectious"
"storj.io/storj/pkg/eestream"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pointerdb/pdbclient"
"storj.io/storj/pkg/storage/meta"
"storj.io/storj/pkg/storj"
)
// Stripe keeps track of a stripe's index and its parent segment
type Stripe struct {
Index int
Segment *pb.Pointer
}
// Cursor keeps track of audit location in pointer db
type Cursor struct {
pointers pdbclient.Client
lastPath storj.Path
mutex sync.Mutex
}
// NewCursor creates a Cursor which iterates over pointer db
func NewCursor(pointers pdbclient.Client) *Cursor {
return &Cursor{pointers: pointers}
}
// NextStripe returns a random stripe to be audited
func (cursor *Cursor) NextStripe(ctx context.Context) (stripe *Stripe, err error) {
cursor.mutex.Lock()
defer cursor.mutex.Unlock()
var pointerItems []pdbclient.ListItem
var path storj.Path
var more bool
if cursor.lastPath == "" {
pointerItems, more, err = cursor.pointers.List(ctx, "", "", "", true, 0, meta.None)
} else {
pointerItems, more, err = cursor.pointers.List(ctx, "", cursor.lastPath, "", true, 0, meta.None)
}
if err != nil {
return nil, err
}
// get random pointer
pointerItem, err := getRandomPointer(pointerItems)
if err != nil {
return nil, err
}
// get path
path = pointerItem.Path
// keep track of last path listed
if !more {
cursor.lastPath = ""
} else {
cursor.lastPath = pointerItems[len(pointerItems)-1].Path
}
// get pointer info
pointer, err := cursor.pointers.Get(ctx, path)
if err != nil {
return nil, err
}
// create the erasure scheme so we can get the stripe size
es, err := makeErasureScheme(pointer.GetRemote().GetRedundancy())
if err != nil {
return nil, err
}
//get random stripe
index, err := getRandomStripe(es, pointer)
if err != nil {
return nil, err
}
return &Stripe{Index: index, Segment: pointer}, nil
}
// create the erasure scheme
func makeErasureScheme(rs *pb.RedundancyScheme) (eestream.ErasureScheme, error) {
fc, err := infectious.NewFEC(int(rs.GetMinReq()), int(rs.GetTotal()))
if err != nil {
return nil, err
}
es := eestream.NewRSScheme(fc, int(rs.GetErasureShareSize()))
return es, nil
}
func getRandomStripe(es eestream.ErasureScheme, pointer *pb.Pointer) (index int, err error) {
stripeSize := es.StripeSize()
randomStripeIndex, err := rand.Int(rand.Reader, big.NewInt(pointer.GetSize()/int64(stripeSize)))
if err != nil {
return -1, err
}
return int(randomStripeIndex.Int64()), nil
}
func getRandomPointer(pointerItems []pdbclient.ListItem) (pointer pdbclient.ListItem, err error) {
randomNum, err := rand.Int(rand.Reader, big.NewInt(int64(len(pointerItems))))
if err != nil {
return pdbclient.ListItem{}, err
}
randomNumInt64 := randomNum.Int64()
pointerItem := pointerItems[randomNumInt64]
return pointerItem, nil
}