Skip to content

Commit

Permalink
satellite/accounting/live: Use Redis client directly
Browse files Browse the repository at this point in the history
We have to adapt the live accounting to allow the packages that use it
to differentiate about errors for being able to ignore them and make our
satellite resilient to Redis downtime.

For differentiating errors we should make changes in the live accounting
but also in the storage/redis.Client, however, we may need to do some
dirty workarounds or break other parts of the implementation that
depends on it.

On the other hand we want to get rid of the storage/redis.Client because
it has more functionality that the one that we are using and some
process has been started to remove it.

Hence, we have refactored the live accounting to directly use the Redis
client library for later on (in a future commit) adapt the satellite for
being resilient to Redis downtime.

Last but not least, a test for expired bandwidth keys have been added
and with it a bug was spotted and fix it.

Change-Id: Ibd191522cd20f6a9a15e5ccb7beb83a678e530ff
  • Loading branch information
ifraixedes committed Jan 12, 2021
1 parent 1ad69b9 commit ce26616
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 172 deletions.
16 changes: 16 additions & 0 deletions satellite/accounting/common.go
Expand Up @@ -6,6 +6,8 @@ package accounting
import (
"time"

"github.com/zeebo/errs"

"storj.io/common/storj"
)

Expand All @@ -19,6 +21,20 @@ const (
LastRollup = "LastRollup"
)

var (
// ErrInvalidArgument is returned when a function argument has an invalid
// business domain value.
ErrInvalidArgument = errs.Class("invalid argument")
// ErrSystemOrNetError is returned when the used storage backend returns an
// internal system or network error.
ErrSystemOrNetError = errs.Class("backend system error")
// ErrKeyNotFound is returned when the key is not found in the cache.
ErrKeyNotFound = errs.Class("key not found")
// ErrUnexpectedValue is returned when an unexpected value according the
// business domain is in the cache.
ErrUnexpectedValue = errs.Class("unexpected value")
)

// CSVRow represents data from QueryPaymentInfo without exposing dbx.
type CSVRow struct {
NodeID storj.NodeID
Expand Down
28 changes: 28 additions & 0 deletions satellite/accounting/db.go
Expand Up @@ -203,12 +203,40 @@ type ProjectAccounting interface {

// Cache stores live information about project storage which has not yet been synced to ProjectAccounting.
//
// All the implementations must follow the convention of returning errors of one
// of the classes defined in this package.
//
// All the methods return:
//
// ErrInvalidArgument: an implementation may return if some parameter contain a
// value which isn't accepted, nonetheless, not all the implementations impose
// the same constraints on them.
//
// ErrSystemOrNetError: any method will return this if there is an error with
// the underlining system or the network.
//
// ErrKeyNotFound: returned when a key is not found.
//
// ErrUnexpectedValue: returned when a key or value stored in the underlying
// system isn't of the expected format or type according the business domain.
//
// architecture: Database
type Cache interface {
// GetProjectStorageUsage returns the project's storage usage.
GetProjectStorageUsage(ctx context.Context, projectID uuid.UUID) (totalUsed int64, err error)
// GetProjectBandwidthUsage returns the project's bandwidth usage.
GetProjectBandwidthUsage(ctx context.Context, projectID uuid.UUID, now time.Time) (currentUsed int64, err error)
// UpdateProjectBandthUsage updates the project's bandwidth usage increasing
// it. The projectID is inserted to the increment when it doesn't exists,
// hence this method will never return ErrKeyNotFound error's class.
UpdateProjectBandwidthUsage(ctx context.Context, projectID uuid.UUID, increment int64, ttl time.Duration, now time.Time) error
// AddProjectStorageUsage adds to the projects storage usage the spacedUsed.
// The projectID is inserted to the spaceUsed when it doesn't exists, hence
// this method will never return ErrKeyNotFound.
AddProjectStorageUsage(ctx context.Context, projectID uuid.UUID, spaceUsed int64) error
// GetAllProjectTotals return the total projects' storage used space.
GetAllProjectTotals(ctx context.Context) (map[uuid.UUID]int64, error)
// Close the client, releasing any open resources. Once it's called any other
// method must be called.
Close() error
}
11 changes: 10 additions & 1 deletion satellite/accounting/live/cache.go
Expand Up @@ -28,6 +28,15 @@ type Config struct {

// NewCache creates a new accounting.Cache instance using the type specified backend in
// the provided config.
//
// The cache instance may be returned despite of returning the
// accounting.ErrSystemOrNetError because some backends allows to reconnect on
// each operation if the connection was not established or it was disconnected,
// which is what it could happen at the moment to instance it and the cache will
// work one the backend system will be reachable later on.
// For this reason, the components that uses the cache should operate despite
// the backend is not responding successfully although their service is
// degraded.
func NewCache(log *zap.Logger, config Config) (accounting.Cache, error) {
parts := strings.SplitN(config.StorageBackend, ":", 2)
var backendType string
Expand All @@ -38,7 +47,7 @@ func NewCache(log *zap.Logger, config Config) (accounting.Cache, error) {
backendType = parts[0]
switch backendType {
case "redis":
return newRedisLiveAccounting(log, config.StorageBackend)
return newRedisLiveAccounting(config.StorageBackend)
default:
return nil, Error.New("unrecognized live accounting backend specifier %q. Currently only redis is supported", backendType)
}
Expand Down

0 comments on commit ce26616

Please sign in to comment.