267506bb20
metabase has become a central concept and it's more suitable for it to be directly nested under satellite rather than being part of metainfo. metainfo is going to be the "endpoint" logic for handling requests. Change-Id: I53770d6761ac1e9a1283b5aa68f471b21e784198
193 lines
5.2 KiB
Go
193 lines
5.2 KiB
Go
// Copyright (C) 2020 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package metabase
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/binary"
|
|
|
|
"github.com/jackc/pgtype"
|
|
|
|
"storj.io/common/storj"
|
|
)
|
|
|
|
// !!!! NB !!!!
|
|
//
|
|
// Should we use protobuf here?
|
|
|
|
type encryptionParameters struct {
|
|
*storj.EncryptionParameters
|
|
}
|
|
|
|
// Check that EncryptionParameters layout doesn't change.
|
|
var _ struct {
|
|
CipherSuite storj.CipherSuite
|
|
BlockSize int32
|
|
} = storj.EncryptionParameters{}
|
|
|
|
// Value implements sql/driver.Valuer interface.
|
|
func (params encryptionParameters) Value() (driver.Value, error) {
|
|
var bytes [8]byte
|
|
bytes[0] = byte(params.CipherSuite)
|
|
binary.LittleEndian.PutUint32(bytes[1:], uint32(params.BlockSize))
|
|
return int64(binary.LittleEndian.Uint64(bytes[:])), nil
|
|
}
|
|
|
|
// Scan implements sql.Scanner interface.
|
|
func (params encryptionParameters) Scan(value interface{}) error {
|
|
switch value := value.(type) {
|
|
case int64:
|
|
var bytes [8]byte
|
|
binary.LittleEndian.PutUint64(bytes[:], uint64(value))
|
|
params.CipherSuite = storj.CipherSuite(bytes[0])
|
|
params.BlockSize = int32(binary.LittleEndian.Uint32(bytes[1:]))
|
|
return nil
|
|
default:
|
|
return Error.New("unable to scan %T into EncryptionParameters", value)
|
|
}
|
|
}
|
|
|
|
// Value implements sql/driver.Valuer interface.
|
|
func (params SegmentPosition) Value() (driver.Value, error) {
|
|
return int64(params.Encode()), nil
|
|
}
|
|
|
|
// Scan implements sql.Scanner interface.
|
|
func (params *SegmentPosition) Scan(value interface{}) error {
|
|
switch value := value.(type) {
|
|
case int64:
|
|
*params = SegmentPositionFromEncoded(uint64(value))
|
|
return nil
|
|
default:
|
|
return Error.New("unable to scan %T into EncryptionParameters", value)
|
|
}
|
|
}
|
|
|
|
type redundancyScheme struct {
|
|
*storj.RedundancyScheme
|
|
}
|
|
|
|
// Check that RedundancyScheme layout doesn't change.
|
|
var _ struct {
|
|
Algorithm storj.RedundancyAlgorithm
|
|
ShareSize int32
|
|
RequiredShares int16
|
|
RepairShares int16
|
|
OptimalShares int16
|
|
TotalShares int16
|
|
} = storj.RedundancyScheme{}
|
|
|
|
func (params redundancyScheme) Value() (driver.Value, error) {
|
|
switch {
|
|
case params.ShareSize < 0 || params.ShareSize >= 1<<24:
|
|
return nil, Error.New("invalid share size %v", params.ShareSize)
|
|
case params.RequiredShares < 0 || params.RequiredShares >= 1<<8:
|
|
return nil, Error.New("invalid required shares %v", params.RequiredShares)
|
|
case params.RepairShares < 0 || params.RepairShares >= 1<<8:
|
|
return nil, Error.New("invalid repair shares %v", params.RepairShares)
|
|
case params.OptimalShares < 0 || params.OptimalShares >= 1<<8:
|
|
return nil, Error.New("invalid optimal shares %v", params.OptimalShares)
|
|
case params.TotalShares < 0 || params.TotalShares >= 1<<8:
|
|
return nil, Error.New("invalid total shares %v", params.TotalShares)
|
|
}
|
|
|
|
var bytes [8]byte
|
|
bytes[0] = byte(params.Algorithm)
|
|
|
|
// little endian uint32
|
|
bytes[1] = byte(params.ShareSize >> 0)
|
|
bytes[2] = byte(params.ShareSize >> 8)
|
|
bytes[3] = byte(params.ShareSize >> 16)
|
|
|
|
bytes[4] = byte(params.RequiredShares)
|
|
bytes[5] = byte(params.RepairShares)
|
|
bytes[6] = byte(params.OptimalShares)
|
|
bytes[7] = byte(params.TotalShares)
|
|
|
|
return int64(binary.LittleEndian.Uint64(bytes[:])), nil
|
|
}
|
|
|
|
func (params redundancyScheme) Scan(value interface{}) error {
|
|
switch value := value.(type) {
|
|
case int64:
|
|
var bytes [8]byte
|
|
binary.LittleEndian.PutUint64(bytes[:], uint64(value))
|
|
|
|
params.Algorithm = storj.RedundancyAlgorithm(bytes[0])
|
|
|
|
// little endian uint32
|
|
params.ShareSize = int32(bytes[1]) | int32(bytes[2])<<8 | int32(bytes[3])<<16
|
|
|
|
params.RequiredShares = int16(bytes[4])
|
|
params.RepairShares = int16(bytes[5])
|
|
params.OptimalShares = int16(bytes[6])
|
|
params.TotalShares = int16(bytes[7])
|
|
|
|
return nil
|
|
default:
|
|
return Error.New("unable to scan %T into RedundancyScheme", value)
|
|
}
|
|
}
|
|
|
|
// Value implements sql/driver.Valuer interface.
|
|
func (pieces Pieces) Value() (driver.Value, error) {
|
|
if len(pieces) == 0 {
|
|
arr := &pgtype.ByteaArray{Status: pgtype.Null}
|
|
return arr.Value()
|
|
}
|
|
|
|
elems := make([]pgtype.Bytea, len(pieces))
|
|
for i, piece := range pieces {
|
|
var buf [2 + len(piece.StorageNode)]byte
|
|
binary.BigEndian.PutUint16(buf[0:], piece.Number)
|
|
copy(buf[2:], piece.StorageNode[:])
|
|
|
|
elems[i].Bytes = buf[:]
|
|
elems[i].Status = pgtype.Present
|
|
}
|
|
|
|
arr := &pgtype.ByteaArray{
|
|
Elements: elems,
|
|
Dimensions: []pgtype.ArrayDimension{{Length: int32(len(pieces)), LowerBound: 1}},
|
|
Status: pgtype.Present,
|
|
}
|
|
return arr.Value()
|
|
}
|
|
|
|
type unexpectedDimension struct{}
|
|
type invalidElementLength struct{}
|
|
|
|
func (unexpectedDimension) Error() string { return "unexpected data dimension" }
|
|
func (invalidElementLength) Error() string { return "invalid element length" }
|
|
|
|
// Scan implements sql.Scanner interface.
|
|
func (pieces *Pieces) Scan(value interface{}) error {
|
|
var arr pgtype.ByteaArray
|
|
if err := arr.Scan(value); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(arr.Dimensions) == 0 {
|
|
*pieces = nil
|
|
return nil
|
|
} else if len(arr.Dimensions) != 1 {
|
|
return unexpectedDimension{}
|
|
}
|
|
|
|
scan := make(Pieces, len(arr.Elements))
|
|
for i, elem := range arr.Elements {
|
|
piece := Piece{}
|
|
if len(elem.Bytes) != 2+len(piece.StorageNode) {
|
|
return invalidElementLength{}
|
|
}
|
|
|
|
piece.Number = binary.BigEndian.Uint16(elem.Bytes[0:])
|
|
copy(piece.StorageNode[:], elem.Bytes[2:])
|
|
scan[i] = piece
|
|
}
|
|
|
|
*pieces = scan
|
|
return nil
|
|
}
|