Tracing for get object #135

Merged
fyrchik merged 5 commits from dstepanov-yadro/frostfs-node:feat/OBJECT-3310 into master 2023-04-12 06:52:02 +00:00
95 changed files with 766 additions and 255 deletions

View file

@ -15,6 +15,7 @@ Changelog for FrostFS Node
- Multiple configs support (#44) - Multiple configs support (#44)
- Parameters `nns-name` and `nns-zone` for command `frostfs-cli container create` (#37) - Parameters `nns-name` and `nns-zone` for command `frostfs-cli container create` (#37)
- Tree service now saves the last synchronization height which persists across restarts (#82) - Tree service now saves the last synchronization height which persists across restarts (#82)
- Add tracing support (#135)
### Changed ### Changed
- Change `frostfs_node_engine_container_size` to counting sizes of logical objects - Change `frostfs_node_engine_container_size` to counting sizes of logical objects

View file

@ -5,6 +5,7 @@ import (
"strings" "strings"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
@ -22,8 +23,15 @@ func _client(ctx context.Context) (tree.TreeServiceClient, error) {
return nil, err return nil, err
} }
opts := make([]grpc.DialOption, 1, 2) opts := []grpc.DialOption{
opts[0] = grpc.WithBlock() grpc.WithBlock(),
grpc.WithChainUnaryInterceptor(
tracing.NewGRPCUnaryClientInteceptor(),
),
grpc.WithChainStreamInterceptor(
tracing.NewGRPCStreamClientInterceptor(),
),
}
if !strings.HasPrefix(netAddr.URIAddr(), "grpcs:") { if !strings.HasPrefix(netAddr.URIAddr(), "grpcs:") {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))

View file

@ -33,7 +33,7 @@ func inspectFunc(cmd *cobra.Command, _ []string) {
var prm blobovnicza.GetPrm var prm blobovnicza.GetPrm
prm.SetAddress(addr) prm.SetAddress(addr)
res, err := blz.Get(prm) res, err := blz.Get(cmd.Context(), prm)
common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err)) common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err))
data := res.Object() data := res.Object()

View file

@ -16,6 +16,7 @@ import (
"time" "time"
netmapV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" netmapV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config"
apiclientconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/apiclient" apiclientconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/apiclient"
contractsconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/contracts" contractsconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/contracts"
@ -27,6 +28,7 @@ import (
nodeconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/node" nodeconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/node"
objectconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/object" objectconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/object"
replicatorconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/replicator" replicatorconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/replicator"
tracingconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
netmapCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" netmapCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor"
@ -1055,6 +1057,13 @@ func (c *cfg) reloadConfig(ctx context.Context) {
} }
components = append(components, dCmp{"logger", logPrm.Reload}) components = append(components, dCmp{"logger", logPrm.Reload})
components = append(components, dCmp{"tracing", func() error {
updated, err := tracing.Setup(ctx, *tracingconfig.ToTracingConfig(c.appCfg))
if updated {
c.log.Info("tracing configation updated")
}
return err
}})
if cmp, updated := metricsComponent(c); updated { if cmp, updated := metricsComponent(c); updated {
if cmp.enabled { if cmp.enabled {
cmp.preReload = enableMetricsSvc cmp.preReload = enableMetricsSvc

View file

@ -0,0 +1,31 @@
package tracing
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config"
"git.frostfs.info/TrueCloudLab/frostfs-node/misc"
)
const (
subsection = "tracing"
)
// ToTracingConfig extracts tracing config.
func ToTracingConfig(c *config.Config) *tracing.Config {
return &tracing.Config{
Enabled: config.BoolSafe(c.Sub(subsection), "enabled"),
Exporter: tracing.Exporter(config.StringSafe(c.Sub(subsection), "exporter")),
Endpoint: config.StringSafe(c.Sub(subsection), "endpoint"),
Service: "frostfs-node",
InstanceID: getInstanceIDOrDefault(c),
Version: misc.Version,
}
}
func getInstanceIDOrDefault(c *config.Config) string {
s := config.StringSlice(c.Sub("node"), "addresses")
if len(s) > 0 {
return s[0]
}
return ""
}

View file

@ -7,6 +7,7 @@ import (
"net" "net"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
grpcconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/grpc" grpcconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
"go.uber.org/zap" "go.uber.org/zap"
@ -19,6 +20,12 @@ func initGRPC(c *cfg) {
grpcconfig.IterateEndpoints(c.appCfg, func(sc *grpcconfig.Config) { grpcconfig.IterateEndpoints(c.appCfg, func(sc *grpcconfig.Config) {
serverOpts := []grpc.ServerOption{ serverOpts := []grpc.ServerOption{
grpc.MaxSendMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize),
grpc.ChainUnaryInterceptor(
tracing.NewGRPCUnaryServerInterceptor(),
),
grpc.ChainStreamInterceptor(
tracing.NewGRPCStreamServerInterceptor(),
),
} }
tlsCfg := sc.TLS() tlsCfg := sc.TLS()

View file

@ -87,6 +87,8 @@ func initApp(ctx context.Context, c *cfg) {
initAndLog(c, pprof.name, pprof.init) initAndLog(c, pprof.name, pprof.init)
initAndLog(c, metrics.name, metrics.init) initAndLog(c, metrics.name, metrics.init)
initAndLog(c, "tracing", func(c *cfg) { initTracing(ctx, c) })
initLocalStorage(c) initLocalStorage(c)
initAndLog(c, "storage engine", func(c *cfg) { initAndLog(c, "storage engine", func(c *cfg) {
@ -100,7 +102,7 @@ func initApp(ctx context.Context, c *cfg) {
initAndLog(c, "container", func(c *cfg) { initContainerService(ctx, c) }) initAndLog(c, "container", func(c *cfg) { initContainerService(ctx, c) })
initAndLog(c, "session", initSessionService) initAndLog(c, "session", initSessionService)
initAndLog(c, "reputation", func(c *cfg) { initReputationService(ctx, c) }) initAndLog(c, "reputation", func(c *cfg) { initReputationService(ctx, c) })
initAndLog(c, "notification", initNotifications) initAndLog(c, "notification", func(c *cfg) { initNotifications(ctx, c) })
initAndLog(c, "object", initObjectService) initAndLog(c, "object", initObjectService)
initAndLog(c, "tree", initTreeService) initAndLog(c, "tree", initTreeService)
initAndLog(c, "control", initControlService) initAndLog(c, "control", initControlService)

View file

@ -23,7 +23,7 @@ type notificationSource struct {
defaultTopic string defaultTopic string
} }
func (n *notificationSource) Iterate(epoch uint64, handler func(topic string, addr oid.Address)) { func (n *notificationSource) Iterate(ctx context.Context, epoch uint64, handler func(topic string, addr oid.Address)) {
log := n.l.With(zap.Uint64("epoch", epoch)) log := n.l.With(zap.Uint64("epoch", epoch))
listRes, err := n.e.ListContainers(engine.ListContainersPrm{}) listRes, err := n.e.ListContainers(engine.ListContainersPrm{})
@ -51,7 +51,7 @@ func (n *notificationSource) Iterate(epoch uint64, handler func(topic string, ad
} }
for _, a := range selectRes.AddressList() { for _, a := range selectRes.AddressList() {
err = n.processAddress(a, handler) err = n.processAddress(ctx, a, handler)
if err != nil { if err != nil {
log.Error("notificator: could not process object", log.Error("notificator: could not process object",
zap.Stringer("address", a), zap.Stringer("address", a),
@ -66,13 +66,14 @@ func (n *notificationSource) Iterate(epoch uint64, handler func(topic string, ad
} }
func (n *notificationSource) processAddress( func (n *notificationSource) processAddress(
ctx context.Context,
a oid.Address, a oid.Address,
h func(topic string, addr oid.Address), h func(topic string, addr oid.Address),
) error { ) error {
var prm engine.HeadPrm var prm engine.HeadPrm
prm.WithAddress(a) prm.WithAddress(a)
res, err := n.e.Head(prm) res, err := n.e.Head(ctx, prm)
if err != nil { if err != nil {
return err return err
} }
@ -108,7 +109,7 @@ func (n notificationWriter) Notify(topic string, address oid.Address) {
} }
} }
func initNotifications(c *cfg) { func initNotifications(ctx context.Context, c *cfg) {
if nodeconfig.Notification(c.appCfg).Enabled() { if nodeconfig.Notification(c.appCfg).Enabled() {
topic := nodeconfig.Notification(c.appCfg).DefaultTopic() topic := nodeconfig.Notification(c.appCfg).DefaultTopic()
pubKey := hex.EncodeToString(c.cfgNodeInfo.localInfo.PublicKey()) pubKey := hex.EncodeToString(c.cfgNodeInfo.localInfo.PublicKey())
@ -151,7 +152,7 @@ func initNotifications(c *cfg) {
addNewEpochAsyncNotificationHandler(c, func(e event.Event) { addNewEpochAsyncNotificationHandler(c, func(e event.Event) {
ev := e.(netmap.NewEpoch) ev := e.(netmap.NewEpoch)
n.ProcessEpoch(ev.EpochNumber()) n.ProcessEpoch(ctx, ev.EpochNumber())
}) })
} }
} }

View file

@ -0,0 +1,31 @@
package main
import (
"context"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
tracingconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/tracing"
"go.uber.org/zap"
)
func initTracing(ctx context.Context, c *cfg) {
conf := tracingconfig.ToTracingConfig(c.appCfg)
_, err := tracing.Setup(ctx, *conf)
if err != nil {
c.log.Error("failed init tracing", zap.Error(err))
}
c.closers = append(c.closers, closer{
name: "tracing",
fn: func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
err := tracing.Shutdown(ctx) //cfg context cancels before close
if err != nil {
c.log.Error("failed shutdown tracing", zap.Error(err))
}
},
})
}

View file

@ -184,3 +184,7 @@ FROSTFS_STORAGE_SHARD_1_PILORAMA_MAX_BATCH_SIZE=100
FROSTFS_STORAGE_SHARD_1_GC_REMOVER_BATCH_SIZE=200 FROSTFS_STORAGE_SHARD_1_GC_REMOVER_BATCH_SIZE=200
#### Sleep interval between data remover tacts #### Sleep interval between data remover tacts
FROSTFS_STORAGE_SHARD_1_GC_REMOVER_SLEEP_INTERVAL=5m FROSTFS_STORAGE_SHARD_1_GC_REMOVER_SLEEP_INTERVAL=5m
FROSTFS_TRACING_ENABLED=true
FROSTFS_TRACING_ENDPOINT="localhost"
FROSTFS_TRACING_EXPORTER="otlp_grpc"

View file

@ -243,5 +243,10 @@
} }
} }
} }
},
"tracing": {
"enabled": true,
"endpoint": "localhost:9090",
"exporter": "otlp_grpc"
} }
} }

View file

@ -214,3 +214,9 @@ storage:
path: tmp/1/blob/pilorama.db path: tmp/1/blob/pilorama.db
no_sync: true # USE WITH CAUTION. Return to user before pages have been persisted. no_sync: true # USE WITH CAUTION. Return to user before pages have been persisted.
perm: 0644 # permission to use for the database file and intermediate directories perm: 0644 # permission to use for the database file and intermediate directories
tracing:
enabled: true
exporter: "otlp_grpc"
endpoint: "localhost"

28
go.mod
View file

@ -3,7 +3,7 @@ module git.frostfs.info/TrueCloudLab/frostfs-node
go 1.18 go 1.18
require ( require (
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703 git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.0
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230316081442-bec77f280a85 git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230316081442-bec77f280a85
git.frostfs.info/TrueCloudLab/hrw v1.2.0 git.frostfs.info/TrueCloudLab/hrw v1.2.0
@ -20,7 +20,6 @@ require (
github.com/multiformats/go-multiaddr v0.8.0 github.com/multiformats/go-multiaddr v0.8.0
github.com/nats-io/nats.go v1.22.1 github.com/nats-io/nats.go v1.22.1
github.com/nspcc-dev/neo-go v0.100.1 github.com/nspcc-dev/neo-go v0.100.1
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb // indirect
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/panjf2000/ants/v2 v2.4.0 github.com/panjf2000/ants/v2 v2.4.0
github.com/paulmach/orb v0.2.2 github.com/paulmach/orb v0.2.2
@ -29,14 +28,16 @@ require (
github.com/spf13/cobra v1.6.1 github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0 github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.2
go.etcd.io/bbolt v1.3.6 go.etcd.io/bbolt v1.3.6
go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/trace v1.14.0
go.uber.org/atomic v1.10.0 go.uber.org/atomic v1.10.0
go.uber.org/zap v1.24.0 go.uber.org/zap v1.24.0
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/term v0.3.0 golang.org/x/term v0.5.0
google.golang.org/grpc v1.52.0 google.golang.org/grpc v1.53.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -47,15 +48,19 @@ require (
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect
github.com/benbjohnson/clock v1.1.0 // indirect github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect github.com/golang/snappy v0.0.3 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/holiman/uint256 v1.2.0 // indirect github.com/holiman/uint256 v1.2.0 // indirect
@ -76,6 +81,7 @@ require (
github.com/nats-io/nkeys v0.3.0 // indirect github.com/nats-io/nkeys v0.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb // indirect
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
@ -90,12 +96,18 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
github.com/twmb/murmur3 v1.1.5 // indirect github.com/twmb/murmur3 v1.1.5 // indirect
github.com/urfave/cli v1.22.5 // indirect github.com/urfave/cli v1.22.5 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.4.0 // indirect golang.org/x/crypto v0.4.0 // indirect
golang.org/x/net v0.4.0 // indirect golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )

BIN
go.sum

Binary file not shown.

View file

@ -1,6 +1,7 @@
package blobovnicza package blobovnicza
import ( import (
"context"
"errors" "errors"
"math/rand" "math/rand"
"os" "os"
@ -39,7 +40,7 @@ func testGet(t *testing.T, blz *Blobovnicza, addr oid.Address, expObj []byte, as
pGet.SetAddress(addr) pGet.SetAddress(addr)
// try to read object from Blobovnicza // try to read object from Blobovnicza
res, err := blz.Get(pGet) res, err := blz.Get(context.Background(), pGet)
if assertErr != nil { if assertErr != nil {
require.True(t, assertErr(err)) require.True(t, assertErr(err))
} else { } else {

View file

@ -1,12 +1,16 @@
package blobovnicza package blobovnicza
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/util/slice"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// GetPrm groups the parameters of Get operation. // GetPrm groups the parameters of Get operation.
@ -39,7 +43,13 @@ var errInterruptForEach = errors.New("interrupt for-each")
// //
// Returns an error of type apistatus.ObjectNotFound if the requested object is not // Returns an error of type apistatus.ObjectNotFound if the requested object is not
// presented in Blobovnicza. // presented in Blobovnicza.
func (b *Blobovnicza) Get(prm GetPrm) (GetRes, error) { func (b *Blobovnicza) Get(ctx context.Context, prm GetPrm) (GetRes, error) {
_, span := tracing.StartSpanFromContext(ctx, "Blobovnicza.Get",
trace.WithAttributes(
attribute.String("address", prm.addr.EncodeToString()),
))
defer span.End()
var ( var (
data []byte data []byte
addrKey = addressKey(prm.addr) addrKey = addressKey(prm.addr)

View file

@ -1,6 +1,7 @@
package blobovnicza package blobovnicza
import ( import (
"context"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -56,7 +57,7 @@ func TestBlobovnicza_Get(t *testing.T) {
prmGet.SetAddress(addr) prmGet.SetAddress(addr)
checkObj := func() { checkObj := func() {
res, err := blz.Get(prmGet) res, err := blz.Get(context.Background(), prmGet)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, obj, res.Object()) require.Equal(t, obj, res.Object())

View file

@ -1,15 +1,27 @@
package blobovniczatree package blobovniczatree
import ( import (
"context"
"encoding/hex"
"path/filepath" "path/filepath"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
// Exists implements common.Storage. // Exists implements common.Storage.
func (b *Blobovniczas) Exists(prm common.ExistsPrm) (common.ExistsRes, error) { func (b *Blobovniczas) Exists(ctx context.Context, prm common.ExistsPrm) (common.ExistsRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Blobovniczas.Exists",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
))
defer span.End()
if prm.StorageID != nil { if prm.StorageID != nil {
id := blobovnicza.NewIDFromBytes(prm.StorageID) id := blobovnicza.NewIDFromBytes(prm.StorageID)
blz, err := b.openBlobovnicza(id.String()) blz, err := b.openBlobovnicza(id.String())
@ -32,7 +44,7 @@ func (b *Blobovniczas) Exists(prm common.ExistsPrm) (common.ExistsRes, error) {
_, ok := activeCache[dirPath] _, ok := activeCache[dirPath]
_, err := b.getObjectFromLevel(gPrm, p, !ok) _, err := b.getObjectFromLevel(ctx, gPrm, p, !ok)
if err != nil { if err != nil {
if !blobovnicza.IsErrNotFound(err) { if !blobovnicza.IsErrNotFound(err) {
b.log.Debug("could not get object from level", b.log.Debug("could not get object from level",

View file

@ -1,6 +1,7 @@
package blobovniczatree package blobovniczatree
import ( import (
"context"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -44,7 +45,7 @@ func TestExistsInvalidStorageID(t *testing.T) {
storageID[0]-- storageID[0]--
} }
res, err := b.Exists(common.ExistsPrm{Address: addr, StorageID: storageID}) res, err := b.Exists(context.Background(), common.ExistsPrm{Address: addr, StorageID: storageID})
require.NoError(t, err) require.NoError(t, err)
require.False(t, res.Exists) require.False(t, res.Exists)
}) })
@ -57,7 +58,7 @@ func TestExistsInvalidStorageID(t *testing.T) {
require.NoError(t, os.Chmod(badDir, 0)) require.NoError(t, os.Chmod(badDir, 0))
t.Cleanup(func() { _ = os.Chmod(filepath.Join(dir, "9"), os.ModePerm) }) t.Cleanup(func() { _ = os.Chmod(filepath.Join(dir, "9"), os.ModePerm) })
res, err := b.Exists(common.ExistsPrm{Address: addr, StorageID: storageID}) res, err := b.Exists(context.Background(), common.ExistsPrm{Address: addr, StorageID: storageID})
require.Error(t, err) require.Error(t, err)
require.False(t, res.Exists) require.False(t, res.Exists)
}) })

View file

@ -1,14 +1,19 @@
package blobovniczatree package blobovniczatree
import ( import (
"context"
"encoding/hex"
"fmt" "fmt"
"path/filepath" "path/filepath"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -16,7 +21,15 @@ import (
// //
// If blobocvnicza ID is specified, only this blobovnicza is processed. // If blobocvnicza ID is specified, only this blobovnicza is processed.
// Otherwise, all Blobovniczas are processed descending weight. // Otherwise, all Blobovniczas are processed descending weight.
func (b *Blobovniczas) Get(prm common.GetPrm) (res common.GetRes, err error) { func (b *Blobovniczas) Get(ctx context.Context, prm common.GetPrm) (res common.GetRes, err error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Blobovniczas.Get",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
attribute.Bool("raw", prm.Raw),
))
defer span.End()
var bPrm blobovnicza.GetPrm var bPrm blobovnicza.GetPrm
bPrm.SetAddress(prm.Address) bPrm.SetAddress(prm.Address)
@ -27,7 +40,7 @@ func (b *Blobovniczas) Get(prm common.GetPrm) (res common.GetRes, err error) {
return res, err return res, err
} }
return b.getObject(blz, bPrm) return b.getObject(ctx, blz, bPrm)
} }
activeCache := make(map[string]struct{}) activeCache := make(map[string]struct{})
@ -37,7 +50,7 @@ func (b *Blobovniczas) Get(prm common.GetPrm) (res common.GetRes, err error) {
_, ok := activeCache[dirPath] _, ok := activeCache[dirPath]
res, err = b.getObjectFromLevel(bPrm, p, !ok) res, err = b.getObjectFromLevel(ctx, bPrm, p, !ok)
if err != nil { if err != nil {
if !blobovnicza.IsErrNotFound(err) { if !blobovnicza.IsErrNotFound(err) {
b.log.Debug("could not get object from level", b.log.Debug("could not get object from level",
@ -64,7 +77,7 @@ func (b *Blobovniczas) Get(prm common.GetPrm) (res common.GetRes, err error) {
// tries to read object from particular blobovnicza. // tries to read object from particular blobovnicza.
// //
// returns error if object could not be read from any blobovnicza of the same level. // returns error if object could not be read from any blobovnicza of the same level.
func (b *Blobovniczas) getObjectFromLevel(prm blobovnicza.GetPrm, blzPath string, tryActive bool) (common.GetRes, error) { func (b *Blobovniczas) getObjectFromLevel(ctx context.Context, prm blobovnicza.GetPrm, blzPath string, tryActive bool) (common.GetRes, error) {
lvlPath := filepath.Dir(blzPath) lvlPath := filepath.Dir(blzPath)
// try to read from blobovnicza if it is opened // try to read from blobovnicza if it is opened
@ -72,7 +85,7 @@ func (b *Blobovniczas) getObjectFromLevel(prm blobovnicza.GetPrm, blzPath string
v, ok := b.opened.Get(blzPath) v, ok := b.opened.Get(blzPath)
b.lruMtx.Unlock() b.lruMtx.Unlock()
if ok { if ok {
if res, err := b.getObject(v, prm); err == nil { if res, err := b.getObject(ctx, v, prm); err == nil {
return res, err return res, err
} else if !blobovnicza.IsErrNotFound(err) { } else if !blobovnicza.IsErrNotFound(err) {
b.log.Debug("could not read object from opened blobovnicza", b.log.Debug("could not read object from opened blobovnicza",
@ -92,7 +105,7 @@ func (b *Blobovniczas) getObjectFromLevel(prm blobovnicza.GetPrm, blzPath string
b.activeMtx.RUnlock() b.activeMtx.RUnlock()
if ok && tryActive { if ok && tryActive {
if res, err := b.getObject(active.blz, prm); err == nil { if res, err := b.getObject(ctx, active.blz, prm); err == nil {
return res, err return res, err
} else if !blobovnicza.IsErrNotFound(err) { } else if !blobovnicza.IsErrNotFound(err) {
b.log.Debug("could not get object from active blobovnicza", b.log.Debug("could not get object from active blobovnicza",
@ -117,12 +130,12 @@ func (b *Blobovniczas) getObjectFromLevel(prm blobovnicza.GetPrm, blzPath string
return common.GetRes{}, err return common.GetRes{}, err
} }
return b.getObject(blz, prm) return b.getObject(ctx, blz, prm)
} }
// reads object from blobovnicza and returns GetSmallRes. // reads object from blobovnicza and returns GetSmallRes.
func (b *Blobovniczas) getObject(blz *blobovnicza.Blobovnicza, prm blobovnicza.GetPrm) (common.GetRes, error) { func (b *Blobovniczas) getObject(ctx context.Context, blz *blobovnicza.Blobovnicza, prm blobovnicza.GetPrm) (common.GetRes, error) {
res, err := blz.Get(prm) res, err := blz.Get(ctx, prm)
if err != nil { if err != nil {
return common.GetRes{}, err return common.GetRes{}, err
} }

View file

@ -1,14 +1,20 @@
package blobovniczatree package blobovniczatree
import ( import (
"context"
"encoding/hex"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -16,7 +22,16 @@ import (
// //
// If blobocvnicza ID is specified, only this blobovnicza is processed. // If blobocvnicza ID is specified, only this blobovnicza is processed.
// Otherwise, all Blobovniczas are processed descending weight. // Otherwise, all Blobovniczas are processed descending weight.
func (b *Blobovniczas) GetRange(prm common.GetRangePrm) (res common.GetRangeRes, err error) { func (b *Blobovniczas) GetRange(ctx context.Context, prm common.GetRangePrm) (res common.GetRangeRes, err error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Blobovniczas.GetRange",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
attribute.String("offset", strconv.FormatUint(prm.Range.GetOffset(), 10)),
attribute.String("length", strconv.FormatUint(prm.Range.GetLength(), 10)),
))
defer span.End()
if prm.StorageID != nil { if prm.StorageID != nil {
id := blobovnicza.NewIDFromBytes(prm.StorageID) id := blobovnicza.NewIDFromBytes(prm.StorageID)
blz, err := b.openBlobovnicza(id.String()) blz, err := b.openBlobovnicza(id.String())
@ -24,7 +39,7 @@ func (b *Blobovniczas) GetRange(prm common.GetRangePrm) (res common.GetRangeRes,
return common.GetRangeRes{}, err return common.GetRangeRes{}, err
} }
return b.getObjectRange(blz, prm) return b.getObjectRange(ctx, blz, prm)
} }
activeCache := make(map[string]struct{}) activeCache := make(map[string]struct{})
@ -35,7 +50,7 @@ func (b *Blobovniczas) GetRange(prm common.GetRangePrm) (res common.GetRangeRes,
_, ok := activeCache[dirPath] _, ok := activeCache[dirPath]
res, err = b.getRangeFromLevel(prm, p, !ok) res, err = b.getRangeFromLevel(ctx, prm, p, !ok)
if err != nil { if err != nil {
outOfBounds := isErrOutOfRange(err) outOfBounds := isErrOutOfRange(err)
if !outOfBounds && !blobovnicza.IsErrNotFound(err) { if !outOfBounds && !blobovnicza.IsErrNotFound(err) {
@ -68,7 +83,7 @@ func (b *Blobovniczas) GetRange(prm common.GetRangePrm) (res common.GetRangeRes,
// tries to read range of object payload data from particular blobovnicza. // tries to read range of object payload data from particular blobovnicza.
// //
// returns error if object could not be read from any blobovnicza of the same level. // returns error if object could not be read from any blobovnicza of the same level.
func (b *Blobovniczas) getRangeFromLevel(prm common.GetRangePrm, blzPath string, tryActive bool) (common.GetRangeRes, error) { func (b *Blobovniczas) getRangeFromLevel(ctx context.Context, prm common.GetRangePrm, blzPath string, tryActive bool) (common.GetRangeRes, error) {
lvlPath := filepath.Dir(blzPath) lvlPath := filepath.Dir(blzPath)
// try to read from blobovnicza if it is opened // try to read from blobovnicza if it is opened
@ -76,7 +91,7 @@ func (b *Blobovniczas) getRangeFromLevel(prm common.GetRangePrm, blzPath string,
v, ok := b.opened.Get(blzPath) v, ok := b.opened.Get(blzPath)
b.lruMtx.Unlock() b.lruMtx.Unlock()
if ok { if ok {
res, err := b.getObjectRange(v, prm) res, err := b.getObjectRange(ctx, v, prm)
switch { switch {
case err == nil, case err == nil,
isErrOutOfRange(err): isErrOutOfRange(err):
@ -101,7 +116,7 @@ func (b *Blobovniczas) getRangeFromLevel(prm common.GetRangePrm, blzPath string,
b.activeMtx.RUnlock() b.activeMtx.RUnlock()
if ok && tryActive { if ok && tryActive {
res, err := b.getObjectRange(active.blz, prm) res, err := b.getObjectRange(ctx, active.blz, prm)
switch { switch {
case err == nil, case err == nil,
isErrOutOfRange(err): isErrOutOfRange(err):
@ -131,11 +146,11 @@ func (b *Blobovniczas) getRangeFromLevel(prm common.GetRangePrm, blzPath string,
return common.GetRangeRes{}, err return common.GetRangeRes{}, err
} }
return b.getObjectRange(blz, prm) return b.getObjectRange(ctx, blz, prm)
} }
// reads range of object payload data from blobovnicza and returns GetRangeSmallRes. // reads range of object payload data from blobovnicza and returns GetRangeSmallRes.
func (b *Blobovniczas) getObjectRange(blz *blobovnicza.Blobovnicza, prm common.GetRangePrm) (common.GetRangeRes, error) { func (b *Blobovniczas) getObjectRange(ctx context.Context, blz *blobovnicza.Blobovnicza, prm common.GetRangePrm) (common.GetRangeRes, error) {
var gPrm blobovnicza.GetPrm var gPrm blobovnicza.GetPrm
gPrm.SetAddress(prm.Address) gPrm.SetAddress(prm.Address)
@ -143,7 +158,7 @@ func (b *Blobovniczas) getObjectRange(blz *blobovnicza.Blobovnicza, prm common.G
// stores data that is compressed on BlobStor side. // stores data that is compressed on BlobStor side.
// If blobovnicza learns to do the compression itself, // If blobovnicza learns to do the compression itself,
// we can start using GetRange. // we can start using GetRange.
res, err := blz.Get(gPrm) res, err := blz.Get(ctx, gPrm)
if err != nil { if err != nil {
return common.GetRangeRes{}, err return common.GetRangeRes{}, err
} }

View file

@ -1,6 +1,7 @@
package blobstor package blobstor
import ( import (
"context"
"path/filepath" "path/filepath"
"testing" "testing"
@ -62,11 +63,11 @@ func TestCompression(t *testing.T) {
} }
testGet := func(t *testing.T, b *BlobStor, i int) { testGet := func(t *testing.T, b *BlobStor, i int) {
res1, err := b.Get(common.GetPrm{Address: object.AddressOf(smallObj[i])}) res1, err := b.Get(context.Background(), common.GetPrm{Address: object.AddressOf(smallObj[i])})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, smallObj[i], res1.Object) require.Equal(t, smallObj[i], res1.Object)
res2, err := b.Get(common.GetPrm{Address: object.AddressOf(bigObj[i])}) res2, err := b.Get(context.Background(), common.GetPrm{Address: object.AddressOf(bigObj[i])})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, bigObj[i], res2.Object) require.Equal(t, bigObj[i], res2.Object)
} }

View file

@ -1,6 +1,10 @@
package common package common
import "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression" import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
)
// Storage represents key-value object storage. // Storage represents key-value object storage.
// It is used as a building block for a blobstor of a shard. // It is used as a building block for a blobstor of a shard.
@ -16,9 +20,9 @@ type Storage interface {
// This function MUST be called before Open. // This function MUST be called before Open.
SetReportErrorFunc(f func(string, error)) SetReportErrorFunc(f func(string, error))
Get(GetPrm) (GetRes, error) Get(context.Context, GetPrm) (GetRes, error)
GetRange(GetRangePrm) (GetRangeRes, error) GetRange(context.Context, GetRangePrm) (GetRangeRes, error)
Exists(ExistsPrm) (ExistsRes, error) Exists(context.Context, ExistsPrm) (ExistsRes, error)
Put(PutPrm) (PutRes, error) Put(PutPrm) (PutRes, error)
Delete(DeletePrm) (DeleteRes, error) Delete(DeletePrm) (DeleteRes, error)
Iterate(IteratePrm) (IterateRes, error) Iterate(IteratePrm) (IterateRes, error)

View file

@ -1,7 +1,13 @@
package blobstor package blobstor
import ( import (
"context"
"encoding/hex"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -9,15 +15,22 @@ import (
// //
// Returns any error encountered that did not allow // Returns any error encountered that did not allow
// to completely check object existence. // to completely check object existence.
func (b *BlobStor) Exists(prm common.ExistsPrm) (common.ExistsRes, error) { func (b *BlobStor) Exists(ctx context.Context, prm common.ExistsPrm) (common.ExistsRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "BlobStor.Exists",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
))
defer span.End()
b.modeMtx.RLock() b.modeMtx.RLock()
defer b.modeMtx.RUnlock() defer b.modeMtx.RUnlock()
if prm.StorageID != nil { if prm.StorageID != nil {
if len(prm.StorageID) == 0 { if len(prm.StorageID) == 0 {
return b.storage[len(b.storage)-1].Storage.Exists(prm) return b.storage[len(b.storage)-1].Storage.Exists(ctx, prm)
} }
return b.storage[0].Storage.Exists(prm) return b.storage[0].Storage.Exists(ctx, prm)
} }
// If there was an error during existence check below, // If there was an error during existence check below,
@ -31,7 +44,7 @@ func (b *BlobStor) Exists(prm common.ExistsPrm) (common.ExistsRes, error) {
// error | error | log the first error, return the second // error | error | log the first error, return the second
var errors []error var errors []error
for i := range b.storage { for i := range b.storage {
res, err := b.storage[i].Storage.Exists(prm) res, err := b.storage[i].Storage.Exists(ctx, prm)
if err == nil && res.Exists { if err == nil && res.Exists {
return res, nil return res, nil
} else if err != nil { } else if err != nil {

View file

@ -1,6 +1,7 @@
package blobstor package blobstor
import ( import (
"context"
"os" "os"
"testing" "testing"
@ -43,13 +44,13 @@ func TestExists(t *testing.T) {
for i := range objects { for i := range objects {
prm.Address = objectCore.AddressOf(objects[i]) prm.Address = objectCore.AddressOf(objects[i])
res, err := b.Exists(prm) res, err := b.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.True(t, res.Exists) require.True(t, res.Exists)
} }
prm.Address = oidtest.Address() prm.Address = oidtest.Address()
res, err := b.Exists(prm) res, err := b.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.False(t, res.Exists) require.False(t, res.Exists)
@ -60,13 +61,13 @@ func TestExists(t *testing.T) {
// Object exists, first error is logged. // Object exists, first error is logged.
prm.Address = objectCore.AddressOf(objects[0]) prm.Address = objectCore.AddressOf(objects[0])
res, err := b.Exists(prm) res, err := b.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.True(t, res.Exists) require.True(t, res.Exists)
// Object doesn't exist, first error is returned. // Object doesn't exist, first error is returned.
prm.Address = objectCore.AddressOf(objects[1]) prm.Address = objectCore.AddressOf(objects[1])
_, err = b.Exists(prm) _, err = b.Exists(context.Background(), prm)
require.Error(t, err) require.Error(t, err)
require.ErrorIs(t, err, teststore.ErrDiskExploded) require.ErrorIs(t, err, teststore.ErrDiskExploded)
}) })

View file

@ -1,6 +1,7 @@
package fstree package fstree
import ( import (
"context"
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"fmt" "fmt"
@ -11,6 +12,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
@ -19,6 +21,8 @@ import (
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// FSTree represents an object storage as a filesystem tree. // FSTree represents an object storage as a filesystem tree.
@ -208,7 +212,13 @@ func (t *FSTree) Delete(prm common.DeletePrm) (common.DeleteRes, error) {
// Exists returns the path to the file with object contents if it exists in the storage // Exists returns the path to the file with object contents if it exists in the storage
// and an error otherwise. // and an error otherwise.
func (t *FSTree) Exists(prm common.ExistsPrm) (common.ExistsRes, error) { func (t *FSTree) Exists(ctx context.Context, prm common.ExistsPrm) (common.ExistsRes, error) {
_, span := tracing.StartSpanFromContext(ctx, "FSTree.Exists",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
))
defer span.End()
p := t.treePath(prm.Address) p := t.treePath(prm.Address)
_, err := os.Stat(p) _, err := os.Stat(p)
@ -336,16 +346,30 @@ func (t *FSTree) PutStream(addr oid.Address, handler func(*os.File) error) error
} }
// Get returns an object from the storage by address. // Get returns an object from the storage by address.
func (t *FSTree) Get(prm common.GetPrm) (common.GetRes, error) { func (t *FSTree) Get(ctx context.Context, prm common.GetPrm) (common.GetRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "FSTree.Get",
trace.WithAttributes(
attribute.Bool("raw", prm.Raw),
attribute.String("address", prm.Address.EncodeToString()),
))
defer span.End()
p := t.treePath(prm.Address) p := t.treePath(prm.Address)
if _, err := os.Stat(p); os.IsNotExist(err) { if _, err := os.Stat(p); os.IsNotExist(err) {
return common.GetRes{}, logicerr.Wrap(apistatus.ObjectNotFound{}) return common.GetRes{}, logicerr.Wrap(apistatus.ObjectNotFound{})
} }
data, err := os.ReadFile(p) var data []byte
if err != nil { var err error
return common.GetRes{}, err {
_, span := tracing.StartSpanFromContext(ctx, "FSTree.Get.ReadFile")
defer span.End()
data, err = os.ReadFile(p)
if err != nil {
return common.GetRes{}, err
}
} }
data, err = t.Decompress(data) data, err = t.Decompress(data)
@ -362,8 +386,16 @@ func (t *FSTree) Get(prm common.GetPrm) (common.GetRes, error) {
} }
// GetRange implements common.Storage. // GetRange implements common.Storage.
func (t *FSTree) GetRange(prm common.GetRangePrm) (common.GetRangeRes, error) { func (t *FSTree) GetRange(ctx context.Context, prm common.GetRangePrm) (common.GetRangeRes, error) {
res, err := t.Get(common.GetPrm{Address: prm.Address}) ctx, span := tracing.StartSpanFromContext(ctx, "FSTree.GetRange",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("offset", strconv.FormatUint(prm.Range.GetOffset(), 10)),
attribute.String("length", strconv.FormatUint(prm.Range.GetLength(), 10)),
))
defer span.End()
res, err := t.Get(ctx, common.GetPrm{Address: prm.Address})
if err != nil { if err != nil {
return common.GetRangeRes{}, err return common.GetRangeRes{}, err
} }

View file

@ -1,23 +1,36 @@
package blobstor package blobstor
import ( import (
"context"
"encoding/hex"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// Get reads the object from b. // Get reads the object from b.
// If the descriptor is present, only one sub-storage is tried, // If the descriptor is present, only one sub-storage is tried,
// Otherwise, each sub-storage is tried in order. // Otherwise, each sub-storage is tried in order.
func (b *BlobStor) Get(prm common.GetPrm) (common.GetRes, error) { func (b *BlobStor) Get(ctx context.Context, prm common.GetPrm) (common.GetRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "BlobStor.Get",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.Bool("raw", prm.Raw),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
))
defer span.End()
b.modeMtx.RLock() b.modeMtx.RLock()
defer b.modeMtx.RUnlock() defer b.modeMtx.RUnlock()
if prm.StorageID == nil { if prm.StorageID == nil {
for i := range b.storage { for i := range b.storage {
res, err := b.storage[i].Storage.Get(prm) res, err := b.storage[i].Storage.Get(ctx, prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) { if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) {
return res, err return res, err
} }
@ -26,7 +39,7 @@ func (b *BlobStor) Get(prm common.GetPrm) (common.GetRes, error) {
return common.GetRes{}, logicerr.Wrap(apistatus.ObjectNotFound{}) return common.GetRes{}, logicerr.Wrap(apistatus.ObjectNotFound{})
} }
if len(prm.StorageID) == 0 { if len(prm.StorageID) == 0 {
return b.storage[len(b.storage)-1].Storage.Get(prm) return b.storage[len(b.storage)-1].Storage.Get(ctx, prm)
} }
return b.storage[0].Storage.Get(prm) return b.storage[0].Storage.Get(ctx, prm)
} }

View file

@ -1,23 +1,38 @@
package blobstor package blobstor
import ( import (
"context"
"encoding/hex"
"errors" "errors"
"strconv"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// GetRange reads object payload data from b. // GetRange reads object payload data from b.
// If the descriptor is present, only one sub-storage is tried, // If the descriptor is present, only one sub-storage is tried,
// Otherwise, each sub-storage is tried in order. // Otherwise, each sub-storage is tried in order.
func (b *BlobStor) GetRange(prm common.GetRangePrm) (common.GetRangeRes, error) { func (b *BlobStor) GetRange(ctx context.Context, prm common.GetRangePrm) (common.GetRangeRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "BlobStor.GetRange",
trace.WithAttributes(
attribute.String("address", prm.Address.EncodeToString()),
attribute.String("storage_id", hex.EncodeToString(prm.StorageID)),
attribute.String("offset", strconv.FormatUint(prm.Range.GetOffset(), 10)),
attribute.String("length", strconv.FormatUint(prm.Range.GetLength(), 10)),
))
defer span.End()
b.modeMtx.RLock() b.modeMtx.RLock()
defer b.modeMtx.RUnlock() defer b.modeMtx.RUnlock()
if prm.StorageID == nil { if prm.StorageID == nil {
for i := range b.storage { for i := range b.storage {
res, err := b.storage[i].Storage.GetRange(prm) res, err := b.storage[i].Storage.GetRange(ctx, prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) { if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) {
return res, err return res, err
} }
@ -26,7 +41,7 @@ func (b *BlobStor) GetRange(prm common.GetRangePrm) (common.GetRangeRes, error)
return common.GetRangeRes{}, logicerr.Wrap(apistatus.ObjectNotFound{}) return common.GetRangeRes{}, logicerr.Wrap(apistatus.ObjectNotFound{})
} }
if len(prm.StorageID) == 0 { if len(prm.StorageID) == 0 {
return b.storage[len(b.storage)-1].Storage.GetRange(prm) return b.storage[len(b.storage)-1].Storage.GetRange(ctx, prm)
} }
return b.storage[0].Storage.GetRange(prm) return b.storage[0].Storage.GetRange(ctx, prm)
} }

View file

@ -1,6 +1,7 @@
package blobstortest package blobstortest
import ( import (
"context"
"math/rand" "math/rand"
"testing" "testing"
@ -26,7 +27,7 @@ func TestControl(t *testing.T, cons Constructor, min, max uint64) {
prm.StorageID = objects[i].storageID prm.StorageID = objects[i].storageID
prm.Raw = true prm.Raw = true
_, err := s.Get(prm) _, err := s.Get(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
} }

View file

@ -1,6 +1,7 @@
package blobstortest package blobstortest
import ( import (
"context"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
@ -35,18 +36,18 @@ func TestDelete(t *testing.T, cons Constructor, min, max uint64) {
t.Run("exists fail", func(t *testing.T) { t.Run("exists fail", func(t *testing.T) {
prm := common.ExistsPrm{Address: oidtest.Address()} prm := common.ExistsPrm{Address: oidtest.Address()}
res, err := s.Exists(prm) res, err := s.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.False(t, res.Exists) require.False(t, res.Exists)
}) })
t.Run("get fail", func(t *testing.T) { t.Run("get fail", func(t *testing.T) {
prm := common.GetPrm{Address: oidtest.Address()} prm := common.GetPrm{Address: oidtest.Address()}
_, err := s.Get(prm) _, err := s.Get(context.Background(), prm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
t.Run("getrange fail", func(t *testing.T) { t.Run("getrange fail", func(t *testing.T) {
prm := common.GetRangePrm{Address: oidtest.Address()} prm := common.GetRangePrm{Address: oidtest.Address()}
_, err := s.GetRange(prm) _, err := s.GetRange(context.Background(), prm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
}) })
@ -75,7 +76,7 @@ func TestDelete(t *testing.T, cons Constructor, min, max uint64) {
prm.Address = objects[3].addr prm.Address = objects[3].addr
prm.Raw = true prm.Raw = true
res, err := s.Get(prm) res, err := s.Get(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[3].raw, res.RawData) require.Equal(t, objects[3].raw, res.RawData)
}) })

View file

@ -1,6 +1,7 @@
package blobstortest package blobstortest
import ( import (
"context"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
@ -18,7 +19,7 @@ func TestExists(t *testing.T, cons Constructor, min, max uint64) {
t.Run("missing object", func(t *testing.T) { t.Run("missing object", func(t *testing.T) {
prm := common.ExistsPrm{Address: oidtest.Address()} prm := common.ExistsPrm{Address: oidtest.Address()}
res, err := s.Exists(prm) res, err := s.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.False(t, res.Exists) require.False(t, res.Exists)
}) })
@ -29,7 +30,7 @@ func TestExists(t *testing.T, cons Constructor, min, max uint64) {
t.Run("without storage ID", func(t *testing.T) { t.Run("without storage ID", func(t *testing.T) {
prm.StorageID = nil prm.StorageID = nil
res, err := s.Exists(prm) res, err := s.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.True(t, res.Exists) require.True(t, res.Exists)
}) })
@ -37,7 +38,7 @@ func TestExists(t *testing.T, cons Constructor, min, max uint64) {
t.Run("with storage ID", func(t *testing.T) { t.Run("with storage ID", func(t *testing.T) {
prm.StorageID = objects[0].storageID prm.StorageID = objects[0].storageID
res, err := s.Exists(prm) res, err := s.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.True(t, res.Exists) require.True(t, res.Exists)
}) })

View file

@ -1,6 +1,7 @@
package blobstortest package blobstortest
import ( import (
"context"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
@ -19,7 +20,7 @@ func TestGet(t *testing.T, cons Constructor, min, max uint64) {
t.Run("missing object", func(t *testing.T) { t.Run("missing object", func(t *testing.T) {
gPrm := common.GetPrm{Address: oidtest.Address()} gPrm := common.GetPrm{Address: oidtest.Address()}
_, err := s.Get(gPrm) _, err := s.Get(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
@ -29,13 +30,13 @@ func TestGet(t *testing.T, cons Constructor, min, max uint64) {
// With storage ID. // With storage ID.
gPrm.StorageID = objects[i].storageID gPrm.StorageID = objects[i].storageID
res, err := s.Get(gPrm) res, err := s.Get(context.Background(), gPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[i].obj, res.Object) require.Equal(t, objects[i].obj, res.Object)
// Without storage ID. // Without storage ID.
gPrm.StorageID = nil gPrm.StorageID = nil
res, err = s.Get(gPrm) res, err = s.Get(context.Background(), gPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[i].obj, res.Object) require.Equal(t, objects[i].obj, res.Object)
@ -43,7 +44,7 @@ func TestGet(t *testing.T, cons Constructor, min, max uint64) {
gPrm.StorageID = objects[i].storageID gPrm.StorageID = objects[i].storageID
gPrm.Raw = true gPrm.Raw = true
res, err = s.Get(gPrm) res, err = s.Get(context.Background(), gPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[i].raw, res.RawData) require.Equal(t, objects[i].raw, res.RawData)
} }

View file

@ -1,6 +1,7 @@
package blobstortest package blobstortest
import ( import (
"context"
"math" "math"
"testing" "testing"
@ -20,7 +21,7 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
t.Run("missing object", func(t *testing.T) { t.Run("missing object", func(t *testing.T) {
gPrm := common.GetRangePrm{Address: oidtest.Address()} gPrm := common.GetRangePrm{Address: oidtest.Address()}
_, err := s.GetRange(gPrm) _, err := s.GetRange(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
@ -38,14 +39,14 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
t.Run("without storage ID", func(t *testing.T) { t.Run("without storage ID", func(t *testing.T) {
// Without storage ID. // Without storage ID.
res, err := s.GetRange(gPrm) res, err := s.GetRange(context.Background(), gPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, payload[start:stop], res.Data) require.Equal(t, payload[start:stop], res.Data)
}) })
t.Run("with storage ID", func(t *testing.T) { t.Run("with storage ID", func(t *testing.T) {
gPrm.StorageID = objects[0].storageID gPrm.StorageID = objects[0].storageID
res, err := s.GetRange(gPrm) res, err := s.GetRange(context.Background(), gPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, payload[start:stop], res.Data) require.Equal(t, payload[start:stop], res.Data)
}) })
@ -54,7 +55,7 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
gPrm.Range.SetOffset(uint64(len(payload) + 10)) gPrm.Range.SetOffset(uint64(len(payload) + 10))
gPrm.Range.SetLength(10) gPrm.Range.SetLength(10)
_, err := s.GetRange(gPrm) _, err := s.GetRange(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange)) require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange))
}) })
@ -62,7 +63,7 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
gPrm.Range.SetOffset(10) gPrm.Range.SetOffset(10)
gPrm.Range.SetLength(uint64(len(payload))) gPrm.Range.SetLength(uint64(len(payload)))
_, err := s.GetRange(gPrm) _, err := s.GetRange(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange)) require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange))
}) })
@ -70,7 +71,7 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
gPrm.Range.SetOffset(0) gPrm.Range.SetOffset(0)
gPrm.Range.SetLength(1 << 63) gPrm.Range.SetLength(1 << 63)
_, err := s.GetRange(gPrm) _, err := s.GetRange(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange)) require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange))
}) })
@ -78,7 +79,7 @@ func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
gPrm.Range.SetOffset(10) gPrm.Range.SetOffset(10)
gPrm.Range.SetLength(math.MaxUint64 - 2) gPrm.Range.SetLength(math.MaxUint64 - 2)
_, err := s.GetRange(gPrm) _, err := s.GetRange(context.Background(), gPrm)
require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange)) require.ErrorAs(t, err, new(apistatus.ObjectOutOfRange))
}) })
} }

View file

@ -2,6 +2,7 @@
package memstore package memstore
import ( import (
"context"
"fmt" "fmt"
"sync" "sync"
@ -32,7 +33,7 @@ func New(opts ...Option) common.Storage {
return st return st
} }
func (s *memstoreImpl) Get(req common.GetPrm) (common.GetRes, error) { func (s *memstoreImpl) Get(_ context.Context, req common.GetPrm) (common.GetRes, error) {
key := req.Address.EncodeToString() key := req.Address.EncodeToString()
s.mu.RLock() s.mu.RLock()
@ -58,8 +59,8 @@ func (s *memstoreImpl) Get(req common.GetPrm) (common.GetRes, error) {
return common.GetRes{Object: obj, RawData: data}, nil return common.GetRes{Object: obj, RawData: data}, nil
} }
func (s *memstoreImpl) GetRange(req common.GetRangePrm) (common.GetRangeRes, error) { func (s *memstoreImpl) GetRange(ctx context.Context, req common.GetRangePrm) (common.GetRangeRes, error) {
getResp, err := s.Get(common.GetPrm{ getResp, err := s.Get(ctx, common.GetPrm{
Address: req.Address, Address: req.Address,
StorageID: req.StorageID, StorageID: req.StorageID,
}) })
@ -80,7 +81,7 @@ func (s *memstoreImpl) GetRange(req common.GetRangePrm) (common.GetRangeRes, err
}, nil }, nil
} }
func (s *memstoreImpl) Exists(req common.ExistsPrm) (common.ExistsRes, error) { func (s *memstoreImpl) Exists(_ context.Context, req common.ExistsPrm) (common.ExistsRes, error) {
key := req.Address.EncodeToString() key := req.Address.EncodeToString()
s.mu.RLock() s.mu.RLock()

View file

@ -1,6 +1,7 @@
package memstore package memstore
import ( import (
"context"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
@ -32,13 +33,13 @@ func TestSimpleLifecycle(t *testing.T) {
} }
{ {
resp, err := s.Exists(common.ExistsPrm{Address: addr}) resp, err := s.Exists(context.Background(), common.ExistsPrm{Address: addr})
require.NoError(t, err) require.NoError(t, err)
require.True(t, resp.Exists) require.True(t, resp.Exists)
} }
{ {
resp, err := s.Get(common.GetPrm{Address: addr}) resp, err := s.Get(context.Background(), common.GetPrm{Address: addr})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, obj.Payload(), resp.Object.Payload()) require.Equal(t, obj.Payload(), resp.Object.Payload())
} }
@ -47,7 +48,7 @@ func TestSimpleLifecycle(t *testing.T) {
var objRange objectSDK.Range var objRange objectSDK.Range
objRange.SetOffset(256) objRange.SetOffset(256)
objRange.SetLength(512) objRange.SetLength(512)
resp, err := s.GetRange(common.GetRangePrm{ resp, err := s.GetRange(context.Background(), common.GetRangePrm{
Address: addr, Address: addr,
Range: objRange, Range: objRange,
}) })
@ -61,7 +62,7 @@ func TestSimpleLifecycle(t *testing.T) {
} }
{ {
resp, err := s.Exists(common.ExistsPrm{Address: addr}) resp, err := s.Exists(context.Background(), common.ExistsPrm{Address: addr})
require.NoError(t, err) require.NoError(t, err)
require.False(t, resp.Exists) require.False(t, resp.Exists)
} }

View file

@ -1,6 +1,7 @@
package blobstor package blobstor
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"testing" "testing"
@ -119,7 +120,7 @@ func BenchmarkSubstorageReadPerf(b *testing.B) {
b.ResetTimer() b.ResetTimer()
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
_, err := st.Get(common.GetPrm{Address: addrGen.Next()}) _, err := st.Get(context.Background(), common.GetPrm{Address: addrGen.Next()})
require.NoError(b, err) require.NoError(b, err)
} }
}) })

View file

@ -13,6 +13,7 @@
package teststore package teststore
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
@ -140,36 +141,36 @@ func (s *TestStore) SetReportErrorFunc(f func(string, error)) {
} }
} }
func (s *TestStore) Get(req common.GetPrm) (common.GetRes, error) { func (s *TestStore) Get(ctx context.Context, req common.GetPrm) (common.GetRes, error) {
switch { switch {
case s.overrides.Get != nil: case s.overrides.Get != nil:
return s.overrides.Get(req) return s.overrides.Get(req)
case s.st != nil: case s.st != nil:
return s.st.Get(req) return s.st.Get(ctx, req)
default: default:
panic(fmt.Sprintf("unexpected storage call: Get(%+v)", req)) panic(fmt.Sprintf("unexpected storage call: Get(%+v)", req))
} }
} }
func (s *TestStore) GetRange(req common.GetRangePrm) (common.GetRangeRes, error) { func (s *TestStore) GetRange(ctx context.Context, req common.GetRangePrm) (common.GetRangeRes, error) {
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock() defer s.mu.RUnlock()
switch { switch {
case s.overrides.GetRange != nil: case s.overrides.GetRange != nil:
return s.overrides.GetRange(req) return s.overrides.GetRange(req)
case s.st != nil: case s.st != nil:
return s.st.GetRange(req) return s.st.GetRange(ctx, req)
default: default:
panic(fmt.Sprintf("unexpected storage call: GetRange(%+v)", req)) panic(fmt.Sprintf("unexpected storage call: GetRange(%+v)", req))
} }
} }
func (s *TestStore) Exists(req common.ExistsPrm) (common.ExistsRes, error) { func (s *TestStore) Exists(ctx context.Context, req common.ExistsPrm) (common.ExistsRes, error) {
switch { switch {
case s.overrides.Exists != nil: case s.overrides.Exists != nil:
return s.overrides.Exists(req) return s.overrides.Exists(req)
case s.st != nil: case s.st != nil:
return s.st.Exists(req) return s.st.Exists(ctx, req)
default: default:
panic(fmt.Sprintf("unexpected storage call: Exists(%+v)", req)) panic(fmt.Sprintf("unexpected storage call: Exists(%+v)", req))
} }

View file

@ -212,20 +212,20 @@ func TestExecBlocks(t *testing.T) {
require.NoError(t, e.BlockExecution(errBlock)) require.NoError(t, e.BlockExecution(errBlock))
// try to exec some op // try to exec some op
_, err := Head(e, addr) _, err := Head(context.Background(), e, addr)
require.ErrorIs(t, err, errBlock) require.ErrorIs(t, err, errBlock)
// resume executions // resume executions
require.NoError(t, e.ResumeExecution()) require.NoError(t, e.ResumeExecution())
_, err = Head(e, addr) // can be any data-related op _, err = Head(context.Background(), e, addr) // can be any data-related op
require.NoError(t, err) require.NoError(t, err)
// close // close
require.NoError(t, e.Close()) require.NoError(t, e.Close())
// try exec after close // try exec after close
_, err = Head(e, addr) _, err = Head(context.Background(), e, addr)
require.Error(t, err) require.Error(t, err)
// try to resume // try to resume

View file

@ -72,7 +72,7 @@ func (e *StorageEngine) delete(ctx context.Context, prm DeletePrm) (DeleteRes, e
var existsPrm shard.ExistsPrm var existsPrm shard.ExistsPrm
existsPrm.SetAddress(prm.addr) existsPrm.SetAddress(prm.addr)
resExists, err := sh.Exists(existsPrm) resExists, err := sh.Exists(ctx, existsPrm)
if err != nil { if err != nil {
if shard.IsErrRemoved(err) || shard.IsErrObjectExpired(err) { if shard.IsErrRemoved(err) || shard.IsErrObjectExpired(err) {
return true return true

View file

@ -93,7 +93,7 @@ func checkGetError(t *testing.T, e *StorageEngine, addr oid.Address, expected an
var getPrm GetPrm var getPrm GetPrm
getPrm.WithAddress(addr) getPrm.WithAddress(addr)
_, err := e.Get(getPrm) _, err := e.Get(context.Background(), getPrm)
if expected != nil { if expected != nil {
require.ErrorAs(t, err, expected) require.ErrorAs(t, err, expected)
} else { } else {

View file

@ -102,7 +102,7 @@ func TestErrorReporting(t *testing.T) {
te.ng.mtx.RUnlock() te.ng.mtx.RUnlock()
require.NoError(t, err) require.NoError(t, err)
_, err = te.ng.Get(GetPrm{addr: object.AddressOf(obj)}) _, err = te.ng.Get(context.Background(), GetPrm{addr: object.AddressOf(obj)})
require.NoError(t, err) require.NoError(t, err)
checkShardState(t, te.ng, te.shards[0].id, 0, mode.ReadWrite) checkShardState(t, te.ng, te.shards[0].id, 0, mode.ReadWrite)
@ -115,7 +115,7 @@ func TestErrorReporting(t *testing.T) {
} }
for i := uint32(1); i < 3; i++ { for i := uint32(1); i < 3; i++ {
_, err = te.ng.Get(GetPrm{addr: object.AddressOf(obj)}) _, err = te.ng.Get(context.Background(), GetPrm{addr: object.AddressOf(obj)})
require.Error(t, err) require.Error(t, err)
checkShardState(t, te.ng, te.shards[0].id, i, mode.ReadWrite) checkShardState(t, te.ng, te.shards[0].id, i, mode.ReadWrite)
checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite) checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite)
@ -136,7 +136,7 @@ func TestErrorReporting(t *testing.T) {
te.ng.mtx.RUnlock() te.ng.mtx.RUnlock()
require.NoError(t, err) require.NoError(t, err)
_, err = te.ng.Get(GetPrm{addr: object.AddressOf(obj)}) _, err = te.ng.Get(context.Background(), GetPrm{addr: object.AddressOf(obj)})
require.NoError(t, err) require.NoError(t, err)
checkShardState(t, te.ng, te.shards[0].id, 0, mode.ReadWrite) checkShardState(t, te.ng, te.shards[0].id, 0, mode.ReadWrite)
@ -149,14 +149,14 @@ func TestErrorReporting(t *testing.T) {
} }
for i := uint32(1); i < errThreshold; i++ { for i := uint32(1); i < errThreshold; i++ {
_, err = te.ng.Get(GetPrm{addr: object.AddressOf(obj)}) _, err = te.ng.Get(context.Background(), GetPrm{addr: object.AddressOf(obj)})
require.Error(t, err) require.Error(t, err)
checkShardState(t, te.ng, te.shards[0].id, i, mode.ReadWrite) checkShardState(t, te.ng, te.shards[0].id, i, mode.ReadWrite)
checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite) checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite)
} }
for i := uint32(0); i < 2; i++ { for i := uint32(0); i < 2; i++ {
_, err = te.ng.Get(GetPrm{addr: object.AddressOf(obj)}) _, err = te.ng.Get(context.Background(), GetPrm{addr: object.AddressOf(obj)})
require.Error(t, err) require.Error(t, err)
checkShardState(t, te.ng, te.shards[0].id, errThreshold+i, mode.DegradedReadOnly) checkShardState(t, te.ng, te.shards[0].id, errThreshold+i, mode.DegradedReadOnly)
checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite) checkShardState(t, te.ng, te.shards[1].id, 0, mode.ReadWrite)
@ -193,9 +193,9 @@ func TestBlobstorFailback(t *testing.T) {
for i := range objs { for i := range objs {
addr := object.AddressOf(objs[i]) addr := object.AddressOf(objs[i])
_, err = te.ng.Get(GetPrm{addr: addr}) _, err = te.ng.Get(context.Background(), GetPrm{addr: addr})
require.NoError(t, err) require.NoError(t, err)
_, err = te.ng.GetRange(RngPrm{addr: addr}) _, err = te.ng.GetRange(context.Background(), RngPrm{addr: addr})
require.NoError(t, err) require.NoError(t, err)
} }
@ -213,15 +213,15 @@ func TestBlobstorFailback(t *testing.T) {
for i := range objs { for i := range objs {
addr := object.AddressOf(objs[i]) addr := object.AddressOf(objs[i])
getRes, err := te.ng.Get(GetPrm{addr: addr}) getRes, err := te.ng.Get(context.Background(), GetPrm{addr: addr})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objs[i], getRes.Object()) require.Equal(t, objs[i], getRes.Object())
rngRes, err := te.ng.GetRange(RngPrm{addr: addr, off: 1, ln: 10}) rngRes, err := te.ng.GetRange(context.Background(), RngPrm{addr: addr, off: 1, ln: 10})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objs[i].Payload()[1:11], rngRes.Object().Payload()) require.Equal(t, objs[i].Payload()[1:11], rngRes.Object().Payload())
_, err = te.ng.GetRange(RngPrm{addr: addr, off: errSmallSize + 10, ln: 1}) _, err = te.ng.GetRange(context.Background(), RngPrm{addr: addr, off: errSmallSize + 10, ln: 1})
require.ErrorAs(t, err, &apistatus.ObjectOutOfRange{}) require.ErrorAs(t, err, &apistatus.ObjectOutOfRange{})
} }

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
@ -58,7 +59,7 @@ var errMustHaveTwoShards = errors.New("must have at least 1 spare shard")
// Evacuate moves data from one shard to the others. // Evacuate moves data from one shard to the others.
// The shard being moved must be in read-only mode. // The shard being moved must be in read-only mode.
func (e *StorageEngine) Evacuate(prm EvacuateShardPrm) (EvacuateShardRes, error) { func (e *StorageEngine) Evacuate(ctx context.Context, prm EvacuateShardPrm) (EvacuateShardRes, error) {
shardIDs := make([]string, len(prm.shardID)) shardIDs := make([]string, len(prm.shardID))
for i := range prm.shardID { for i := range prm.shardID {
shardIDs[i] = prm.shardID[i].String() shardIDs[i] = prm.shardID[i].String()
@ -83,7 +84,7 @@ func (e *StorageEngine) Evacuate(prm EvacuateShardPrm) (EvacuateShardRes, error)
var res EvacuateShardRes var res EvacuateShardRes
for _, shardID := range shardIDs { for _, shardID := range shardIDs {
if err = e.evacuateShard(shardID, prm, &res, shards, weights, shardsToEvacuate); err != nil { if err = e.evacuateShard(ctx, shardID, prm, &res, shards, weights, shardsToEvacuate); err != nil {
return res, err return res, err
} }
} }
@ -92,7 +93,7 @@ func (e *StorageEngine) Evacuate(prm EvacuateShardPrm) (EvacuateShardRes, error)
return res, nil return res, nil
} }
func (e *StorageEngine) evacuateShard(shardID string, prm EvacuateShardPrm, res *EvacuateShardRes, func (e *StorageEngine) evacuateShard(ctx context.Context, shardID string, prm EvacuateShardPrm, res *EvacuateShardRes,
shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) error { shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) error {
var listPrm shard.ListWithCursorPrm var listPrm shard.ListWithCursorPrm
listPrm.WithCount(defaultEvacuateBatchSize) listPrm.WithCount(defaultEvacuateBatchSize)
@ -113,7 +114,7 @@ func (e *StorageEngine) evacuateShard(shardID string, prm EvacuateShardPrm, res
return err return err
} }
if err = e.evacuateObjects(sh, listRes.AddressList(), prm, res, shards, weights, shardsToEvacuate); err != nil { if err = e.evacuateObjects(ctx, sh, listRes.AddressList(), prm, res, shards, weights, shardsToEvacuate); err != nil {
return err return err
} }
@ -160,7 +161,7 @@ func (e *StorageEngine) getActualShards(shardIDs []string, handlerDefined bool)
return shards, weights, nil return shards, weights, nil
} }
func (e *StorageEngine) evacuateObjects(sh *shard.Shard, toEvacuate []object.AddressWithType, prm EvacuateShardPrm, res *EvacuateShardRes, func (e *StorageEngine) evacuateObjects(ctx context.Context, sh *shard.Shard, toEvacuate []object.AddressWithType, prm EvacuateShardPrm, res *EvacuateShardRes,
shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) error { shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) error {
for i := range toEvacuate { for i := range toEvacuate {
addr := toEvacuate[i].Address addr := toEvacuate[i].Address
@ -168,7 +169,7 @@ func (e *StorageEngine) evacuateObjects(sh *shard.Shard, toEvacuate []object.Add
var getPrm shard.GetPrm var getPrm shard.GetPrm
getPrm.SetAddress(addr) getPrm.SetAddress(addr)
getRes, err := sh.Get(getPrm) getRes, err := sh.Get(ctx, getPrm)
if err != nil { if err != nil {
if prm.ignoreErrors { if prm.ignoreErrors {
continue continue
@ -176,7 +177,7 @@ func (e *StorageEngine) evacuateObjects(sh *shard.Shard, toEvacuate []object.Add
return err return err
} }
if e.tryEvacuateObject(addr, getRes.Object(), sh, res, shards, weights, shardsToEvacuate) { if e.tryEvacuateObject(ctx, addr, getRes.Object(), sh, res, shards, weights, shardsToEvacuate) {
continue continue
} }
@ -195,14 +196,14 @@ func (e *StorageEngine) evacuateObjects(sh *shard.Shard, toEvacuate []object.Add
return nil return nil
} }
func (e *StorageEngine) tryEvacuateObject(addr oid.Address, object *objectSDK.Object, sh *shard.Shard, res *EvacuateShardRes, func (e *StorageEngine) tryEvacuateObject(ctx context.Context, addr oid.Address, object *objectSDK.Object, sh *shard.Shard, res *EvacuateShardRes,
shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) bool { shards []pooledShard, weights []float64, shardsToEvacuate map[string]*shard.Shard) bool {
hrw.SortHasherSliceByWeightValue(shards, weights, hrw.Hash([]byte(addr.EncodeToString()))) hrw.SortHasherSliceByWeightValue(shards, weights, hrw.Hash([]byte(addr.EncodeToString())))
for j := range shards { for j := range shards {
if _, ok := shardsToEvacuate[shards[j].ID().String()]; ok { if _, ok := shardsToEvacuate[shards[j].ID().String()]; ok {
continue continue
} }
putDone, exists := e.putToShard(shards[j].hashedShard, j, shards[j].pool, addr, object) putDone, exists := e.putToShard(ctx, shards[j].hashedShard, j, shards[j].pool, addr, object)
if putDone || exists { if putDone || exists {
if putDone { if putDone {
e.log.Debug("object is moved to another shard", e.log.Debug("object is moved to another shard",

View file

@ -91,7 +91,7 @@ func TestEvacuateShard(t *testing.T) {
var prm GetPrm var prm GetPrm
prm.WithAddress(objectCore.AddressOf(objects[i])) prm.WithAddress(objectCore.AddressOf(objects[i]))
_, err := e.Get(prm) _, err := e.Get(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
} }
} }
@ -102,14 +102,14 @@ func TestEvacuateShard(t *testing.T) {
prm.WithShardIDList(ids[2:3]) prm.WithShardIDList(ids[2:3])
t.Run("must be read-only", func(t *testing.T) { t.Run("must be read-only", func(t *testing.T) {
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.ErrorIs(t, err, shard.ErrMustBeReadOnly) require.ErrorIs(t, err, shard.ErrMustBeReadOnly)
require.Equal(t, 0, res.Count()) require.Equal(t, 0, res.Count())
}) })
require.NoError(t, e.shards[evacuateShardID].SetMode(mode.ReadOnly)) require.NoError(t, e.shards[evacuateShardID].SetMode(mode.ReadOnly))
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objPerShard, res.count) require.Equal(t, objPerShard, res.count)
@ -120,7 +120,7 @@ func TestEvacuateShard(t *testing.T) {
checkHasObjects(t) checkHasObjects(t)
// Calling it again is OK, but all objects are already moved, so no new PUTs should be done. // Calling it again is OK, but all objects are already moved, so no new PUTs should be done.
res, err = e.Evacuate(prm) res, err = e.Evacuate(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 0, res.count) require.Equal(t, 0, res.count)
@ -165,13 +165,13 @@ func TestEvacuateNetwork(t *testing.T) {
var prm EvacuateShardPrm var prm EvacuateShardPrm
prm.shardID = ids[0:1] prm.shardID = ids[0:1]
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.ErrorIs(t, err, errMustHaveTwoShards) require.ErrorIs(t, err, errMustHaveTwoShards)
require.Equal(t, 0, res.Count()) require.Equal(t, 0, res.Count())
prm.handler = acceptOneOf(objects, 2) prm.handler = acceptOneOf(objects, 2)
res, err = e.Evacuate(prm) res, err = e.Evacuate(context.Background(), prm)
require.ErrorIs(t, err, errReplication) require.ErrorIs(t, err, errReplication)
require.Equal(t, 2, res.Count()) require.Equal(t, 2, res.Count())
}) })
@ -185,14 +185,14 @@ func TestEvacuateNetwork(t *testing.T) {
prm.shardID = ids[1:2] prm.shardID = ids[1:2]
prm.handler = acceptOneOf(objects, 2) prm.handler = acceptOneOf(objects, 2)
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.ErrorIs(t, err, errReplication) require.ErrorIs(t, err, errReplication)
require.Equal(t, 2, res.Count()) require.Equal(t, 2, res.Count())
t.Run("no errors", func(t *testing.T) { t.Run("no errors", func(t *testing.T) {
prm.handler = acceptOneOf(objects, 3) prm.handler = acceptOneOf(objects, 3)
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 3, res.Count()) require.Equal(t, 3, res.Count())
}) })
@ -217,14 +217,14 @@ func TestEvacuateNetwork(t *testing.T) {
prm.shardID = evacuateIDs prm.shardID = evacuateIDs
prm.handler = acceptOneOf(objects, totalCount-1) prm.handler = acceptOneOf(objects, totalCount-1)
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.ErrorIs(t, err, errReplication) require.ErrorIs(t, err, errReplication)
require.Equal(t, totalCount-1, res.Count()) require.Equal(t, totalCount-1, res.Count())
t.Run("no errors", func(t *testing.T) { t.Run("no errors", func(t *testing.T) {
prm.handler = acceptOneOf(objects, totalCount) prm.handler = acceptOneOf(objects, totalCount)
res, err := e.Evacuate(prm) res, err := e.Evacuate(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, totalCount, res.Count()) require.Equal(t, totalCount, res.Count())
}) })

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
@ -16,7 +17,7 @@ func (e *StorageEngine) exists(addr oid.Address) (bool, error) {
exists := false exists := false
e.iterateOverSortedShards(addr, func(_ int, sh hashedShard) (stop bool) { e.iterateOverSortedShards(addr, func(_ int, sh hashedShard) (stop bool) {
res, err := sh.Exists(shPrm) res, err := sh.Exists(context.TODO(), shPrm)
if err != nil { if err != nil {
if shard.IsErrRemoved(err) { if shard.IsErrRemoved(err) {
alreadyRemoved = true alreadyRemoved = true

View file

@ -1,14 +1,18 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -43,16 +47,22 @@ func (r GetRes) Object() *objectSDK.Object {
// Returns an error of type apistatus.ObjectAlreadyRemoved if the object has been marked as removed. // Returns an error of type apistatus.ObjectAlreadyRemoved if the object has been marked as removed.
// //
// Returns an error if executions are blocked (see BlockExecution). // Returns an error if executions are blocked (see BlockExecution).
func (e *StorageEngine) Get(prm GetPrm) (res GetRes, err error) { func (e *StorageEngine) Get(ctx context.Context, prm GetPrm) (res GetRes, err error) {
err = e.execIfNotBlocked(func() error { err = e.execIfNotBlocked(func() error {
res, err = e.get(prm) res, err = e.get(ctx, prm)
return err return err
}) })
return return
} }
func (e *StorageEngine) get(prm GetPrm) (GetRes, error) { func (e *StorageEngine) get(ctx context.Context, prm GetPrm) (GetRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.get",
trace.WithAttributes(
attribute.String("address", prm.addr.EncodeToString()),
))
defer span.End()
if e.metrics != nil { if e.metrics != nil {
defer elapsed(e.metrics.AddGetDuration)() defer elapsed(e.metrics.AddGetDuration)()
} }
@ -69,7 +79,7 @@ func (e *StorageEngine) get(prm GetPrm) (GetRes, error) {
Engine: e, Engine: e,
} }
it.tryGetWithMeta() it.tryGetWithMeta(ctx)
if it.SplitInfo != nil { if it.SplitInfo != nil {
return GetRes{}, logicerr.Wrap(objectSDK.NewSplitInfoError(it.SplitInfo)) return GetRes{}, logicerr.Wrap(objectSDK.NewSplitInfoError(it.SplitInfo))
@ -84,7 +94,7 @@ func (e *StorageEngine) get(prm GetPrm) (GetRes, error) {
return GetRes{}, it.OutError return GetRes{}, it.OutError
} }
it.tryGetFromBlobstore() it.tryGetFromBlobstore(ctx)
if it.Object == nil { if it.Object == nil {
return GetRes{}, it.OutError return GetRes{}, it.OutError
@ -116,14 +126,14 @@ type getShardIterator struct {
splitInfoErr *objectSDK.SplitInfoError splitInfoErr *objectSDK.SplitInfoError
} }
func (i *getShardIterator) tryGetWithMeta() { func (i *getShardIterator) tryGetWithMeta(ctx context.Context) {
i.Engine.iterateOverSortedShards(i.Address, func(_ int, sh hashedShard) (stop bool) { i.Engine.iterateOverSortedShards(i.Address, func(_ int, sh hashedShard) (stop bool) {
noMeta := sh.GetMode().NoMetabase() noMeta := sh.GetMode().NoMetabase()
i.ShardPrm.SetIgnoreMeta(noMeta) i.ShardPrm.SetIgnoreMeta(noMeta)
i.HasDegraded = i.HasDegraded || noMeta i.HasDegraded = i.HasDegraded || noMeta
res, err := sh.Get(i.ShardPrm) res, err := sh.Get(ctx, i.ShardPrm)
if err == nil { if err == nil {
i.Object = res.Object() i.Object = res.Object()
return true return true
@ -162,7 +172,7 @@ func (i *getShardIterator) tryGetWithMeta() {
}) })
} }
func (i *getShardIterator) tryGetFromBlobstore() { func (i *getShardIterator) tryGetFromBlobstore(ctx context.Context) {
// If the object is not found but is present in metabase, // If the object is not found but is present in metabase,
// try to fetch it from blobstor directly. If it is found in any // try to fetch it from blobstor directly. If it is found in any
// blobstor, increase the error counter for the shard which contains the meta. // blobstor, increase the error counter for the shard which contains the meta.
@ -174,18 +184,18 @@ func (i *getShardIterator) tryGetFromBlobstore() {
return false return false
} }
res, err := sh.Get(i.ShardPrm) res, err := sh.Get(ctx, i.ShardPrm)
i.Object = res.Object() i.Object = res.Object()
return err == nil return err == nil
}) })
} }
// Get reads object from local storage by provided address. // Get reads object from local storage by provided address.
func Get(storage *StorageEngine, addr oid.Address) (*objectSDK.Object, error) { func Get(ctx context.Context, storage *StorageEngine, addr oid.Address) (*objectSDK.Object, error) {
var getPrm GetPrm var getPrm GetPrm
getPrm.WithAddress(addr) getPrm.WithAddress(addr)
res, err := storage.Get(getPrm) res, err := storage.Get(ctx, getPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,8 +1,10 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
@ -52,16 +54,19 @@ func (r HeadRes) Header() *objectSDK.Object {
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object was inhumed. // Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object was inhumed.
// //
// Returns an error if executions are blocked (see BlockExecution). // Returns an error if executions are blocked (see BlockExecution).
func (e *StorageEngine) Head(prm HeadPrm) (res HeadRes, err error) { func (e *StorageEngine) Head(ctx context.Context, prm HeadPrm) (res HeadRes, err error) {
err = e.execIfNotBlocked(func() error { err = e.execIfNotBlocked(func() error {
res, err = e.head(prm) res, err = e.head(ctx, prm)
return err return err
}) })
return return
} }
func (e *StorageEngine) head(prm HeadPrm) (HeadRes, error) { func (e *StorageEngine) head(ctx context.Context, prm HeadPrm) (HeadRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.head")
defer span.End()
if e.metrics != nil { if e.metrics != nil {
defer elapsed(e.metrics.AddHeadDuration)() defer elapsed(e.metrics.AddHeadDuration)()
} }
@ -81,7 +86,7 @@ func (e *StorageEngine) head(prm HeadPrm) (HeadRes, error) {
shPrm.SetRaw(prm.raw) shPrm.SetRaw(prm.raw)
e.iterateOverSortedShards(prm.addr, func(_ int, sh hashedShard) (stop bool) { e.iterateOverSortedShards(prm.addr, func(_ int, sh hashedShard) (stop bool) {
res, err := sh.Head(shPrm) res, err := sh.Head(ctx, shPrm)
if err != nil { if err != nil {
switch { switch {
case shard.IsErrNotFound(err): case shard.IsErrNotFound(err):
@ -139,11 +144,11 @@ func (e *StorageEngine) head(prm HeadPrm) (HeadRes, error) {
} }
// Head reads object header from local storage by provided address. // Head reads object header from local storage by provided address.
func Head(storage *StorageEngine, addr oid.Address) (*objectSDK.Object, error) { func Head(ctx context.Context, storage *StorageEngine, addr oid.Address) (*objectSDK.Object, error) {
var headPrm HeadPrm var headPrm HeadPrm
headPrm.WithAddress(addr) headPrm.WithAddress(addr)
res, err := storage.Head(headPrm) res, err := storage.Head(ctx, headPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -153,12 +158,12 @@ func Head(storage *StorageEngine, addr oid.Address) (*objectSDK.Object, error) {
// HeadRaw reads object header from local storage by provided address and raw // HeadRaw reads object header from local storage by provided address and raw
// flag. // flag.
func HeadRaw(storage *StorageEngine, addr oid.Address, raw bool) (*objectSDK.Object, error) { func HeadRaw(ctx context.Context, storage *StorageEngine, addr oid.Address, raw bool) (*objectSDK.Object, error) {
var headPrm HeadPrm var headPrm HeadPrm
headPrm.WithAddress(addr) headPrm.WithAddress(addr)
headPrm.WithRaw(raw) headPrm.WithRaw(raw)
res, err := storage.Head(headPrm) res, err := storage.Head(ctx, headPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"context"
"os" "os"
"testing" "testing"
@ -66,7 +67,7 @@ func TestHeadRaw(t *testing.T) {
headPrm.WithAddress(parentAddr) headPrm.WithAddress(parentAddr)
headPrm.WithRaw(true) headPrm.WithRaw(true)
_, err = e.Head(headPrm) _, err = e.Head(context.Background(), headPrm)
require.Error(t, err) require.Error(t, err)
var si *object.SplitInfoError var si *object.SplitInfoError

View file

@ -134,7 +134,7 @@ func (e *StorageEngine) inhumeAddr(ctx context.Context, addr oid.Address, prm sh
if checkExists { if checkExists {
existPrm.SetAddress(addr) existPrm.SetAddress(addr)
exRes, err := sh.Exists(existPrm) exRes, err := sh.Exists(ctx, existPrm)
if err != nil { if err != nil {
if shard.IsErrRemoved(err) || shard.IsErrObjectExpired(err) { if shard.IsErrRemoved(err) || shard.IsErrObjectExpired(err) {
// inhumed once - no need to be inhumed again // inhumed once - no need to be inhumed again

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
@ -69,7 +70,7 @@ func (e *StorageEngine) lockSingle(idCnr cid.ID, locker, locked oid.ID, checkExi
var existsPrm shard.ExistsPrm var existsPrm shard.ExistsPrm
existsPrm.SetAddress(addrLocked) existsPrm.SetAddress(addrLocked)
exRes, err := sh.Exists(existsPrm) exRes, err := sh.Exists(context.TODO(), existsPrm)
if err != nil { if err != nil {
var siErr *objectSDK.SplitInfoError var siErr *objectSDK.SplitInfoError
if !errors.As(err, &siErr) { if !errors.As(err, &siErr) {

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
@ -72,7 +73,7 @@ func (e *StorageEngine) put(prm PutPrm) (PutRes, error) {
return false return false
} }
putDone, exists := e.putToShard(sh, ind, pool, addr, prm.obj) putDone, exists := e.putToShard(context.TODO(), sh, ind, pool, addr, prm.obj)
finished = putDone || exists finished = putDone || exists
return finished return finished
}) })
@ -87,7 +88,7 @@ func (e *StorageEngine) put(prm PutPrm) (PutRes, error) {
// putToShard puts object to sh. // putToShard puts object to sh.
// First return value is true iff put has been successfully done. // First return value is true iff put has been successfully done.
// Second return value is true iff object already exists. // Second return value is true iff object already exists.
func (e *StorageEngine) putToShard(sh hashedShard, ind int, pool util.WorkerPool, addr oid.Address, obj *objectSDK.Object) (bool, bool) { func (e *StorageEngine) putToShard(ctx context.Context, sh hashedShard, ind int, pool util.WorkerPool, addr oid.Address, obj *objectSDK.Object) (bool, bool) {
var putSuccess, alreadyExists bool var putSuccess, alreadyExists bool
exitCh := make(chan struct{}) exitCh := make(chan struct{})
@ -98,7 +99,7 @@ func (e *StorageEngine) putToShard(sh hashedShard, ind int, pool util.WorkerPool
var existPrm shard.ExistsPrm var existPrm shard.ExistsPrm
existPrm.SetAddress(addr) existPrm.SetAddress(addr)
exists, err := sh.Exists(existPrm) exists, err := sh.Exists(ctx, existPrm)
if err != nil { if err != nil {
if shard.IsErrObjectExpired(err) { if shard.IsErrObjectExpired(err) {
// object is already found but // object is already found but

View file

@ -1,14 +1,19 @@
package engine package engine
import ( import (
"context"
"errors" "errors"
"strconv"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -56,16 +61,24 @@ func (r RngRes) Object() *objectSDK.Object {
// Returns ErrRangeOutOfBounds if the requested object range is out of bounds. // Returns ErrRangeOutOfBounds if the requested object range is out of bounds.
// //
// Returns an error if executions are blocked (see BlockExecution). // Returns an error if executions are blocked (see BlockExecution).
func (e *StorageEngine) GetRange(prm RngPrm) (res RngRes, err error) { func (e *StorageEngine) GetRange(ctx context.Context, prm RngPrm) (res RngRes, err error) {
err = e.execIfNotBlocked(func() error { err = e.execIfNotBlocked(func() error {
res, err = e.getRange(prm) res, err = e.getRange(ctx, prm)
return err return err
}) })
return return
} }
func (e *StorageEngine) getRange(prm RngPrm) (RngRes, error) { func (e *StorageEngine) getRange(ctx context.Context, prm RngPrm) (RngRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.getRange",
trace.WithAttributes(
attribute.String("address", prm.addr.EncodeToString()),
attribute.String("offset", strconv.FormatUint(prm.off, 10)),
attribute.String("length", strconv.FormatUint(prm.ln, 10)),
))
defer span.End()
if e.metrics != nil { if e.metrics != nil {
defer elapsed(e.metrics.AddRangeDuration)() defer elapsed(e.metrics.AddRangeDuration)()
} }
@ -83,7 +96,7 @@ func (e *StorageEngine) getRange(prm RngPrm) (RngRes, error) {
Engine: e, Engine: e,
} }
it.tryGetWithMeta() it.tryGetWithMeta(ctx)
if it.SplitInfo != nil { if it.SplitInfo != nil {
return RngRes{}, logicerr.Wrap(objectSDK.NewSplitInfoError(it.SplitInfo)) return RngRes{}, logicerr.Wrap(objectSDK.NewSplitInfoError(it.SplitInfo))
@ -96,7 +109,7 @@ func (e *StorageEngine) getRange(prm RngPrm) (RngRes, error) {
return RngRes{}, it.OutError return RngRes{}, it.OutError
} }
it.tryGetFromBlobstor() it.tryGetFromBlobstor(ctx)
if it.Object == nil { if it.Object == nil {
return RngRes{}, it.OutError return RngRes{}, it.OutError
@ -114,12 +127,12 @@ func (e *StorageEngine) getRange(prm RngPrm) (RngRes, error) {
} }
// GetRange reads object payload range from local storage by provided address. // GetRange reads object payload range from local storage by provided address.
func GetRange(storage *StorageEngine, addr oid.Address, rng *objectSDK.Range) ([]byte, error) { func GetRange(ctx context.Context, storage *StorageEngine, addr oid.Address, rng *objectSDK.Range) ([]byte, error) {
var rangePrm RngPrm var rangePrm RngPrm
rangePrm.WithAddress(addr) rangePrm.WithAddress(addr)
rangePrm.WithPayloadRange(rng) rangePrm.WithPayloadRange(rng)
res, err := storage.GetRange(rangePrm) res, err := storage.GetRange(ctx, rangePrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -141,13 +154,13 @@ type getRangeShardIterator struct {
Engine *StorageEngine Engine *StorageEngine
} }
func (i *getRangeShardIterator) tryGetWithMeta() { func (i *getRangeShardIterator) tryGetWithMeta(ctx context.Context) {
i.Engine.iterateOverSortedShards(i.Address, func(_ int, sh hashedShard) (stop bool) { i.Engine.iterateOverSortedShards(i.Address, func(_ int, sh hashedShard) (stop bool) {
noMeta := sh.GetMode().NoMetabase() noMeta := sh.GetMode().NoMetabase()
i.HasDegraded = i.HasDegraded || noMeta i.HasDegraded = i.HasDegraded || noMeta
i.ShardPrm.SetIgnoreMeta(noMeta) i.ShardPrm.SetIgnoreMeta(noMeta)
res, err := sh.GetRange(i.ShardPrm) res, err := sh.GetRange(ctx, i.ShardPrm)
if err == nil { if err == nil {
i.Object = res.Object() i.Object = res.Object()
return true return true
@ -185,7 +198,7 @@ func (i *getRangeShardIterator) tryGetWithMeta() {
}) })
} }
func (i *getRangeShardIterator) tryGetFromBlobstor() { func (i *getRangeShardIterator) tryGetFromBlobstor(ctx context.Context) {
// If the object is not found but is present in metabase, // If the object is not found but is present in metabase,
// try to fetch it from blobstor directly. If it is found in any // try to fetch it from blobstor directly. If it is found in any
// blobstor, increase the error counter for the shard which contains the meta. // blobstor, increase the error counter for the shard which contains the meta.
@ -197,7 +210,7 @@ func (i *getRangeShardIterator) tryGetFromBlobstor() {
return false return false
} }
res, err := sh.GetRange(i.ShardPrm) res, err := sh.GetRange(ctx, i.ShardPrm)
if shard.IsErrOutOfRange(err) { if shard.IsErrOutOfRange(err) {
var errOutOfRange apistatus.ObjectOutOfRange var errOutOfRange apistatus.ObjectOutOfRange

View file

@ -116,7 +116,7 @@ func (e *StorageEngine) removeObjects(ctx context.Context, ch <-chan oid.Address
var existsPrm shard.ExistsPrm var existsPrm shard.ExistsPrm
existsPrm.SetAddress(addr) existsPrm.SetAddress(addr)
res, err := shards[i].Exists(existsPrm) res, err := shards[i].Exists(ctx, existsPrm)
if err != nil { if err != nil {
return err return err
} else if !res.Exists() { } else if !res.Exists() {

View file

@ -63,6 +63,7 @@ func TestShardOpen(t *testing.T) {
newShard := func() *Shard { newShard := func() *Shard {
return New( return New(
WithID(NewIDFromBytes([]byte{})),
WithLogger(&logger.Logger{Logger: zaptest.NewLogger(t)}), WithLogger(&logger.Logger{Logger: zaptest.NewLogger(t)}),
WithBlobStorOptions( WithBlobStorOptions(
blobstor.WithStorages([]blobstor.SubStorage{ blobstor.WithStorages([]blobstor.SubStorage{
@ -146,6 +147,7 @@ func TestRefillMetabaseCorrupted(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
sh = New( sh = New(
WithID(NewIDFromBytes([]byte{})),
WithBlobStorOptions(blobOpts...), WithBlobStorOptions(blobOpts...),
WithPiloramaOptions(pilorama.WithPath(filepath.Join(dir, "pilorama"))), WithPiloramaOptions(pilorama.WithPath(filepath.Join(dir, "pilorama"))),
WithMetaBaseOptions(meta.WithPath(filepath.Join(dir, "meta_new")), meta.WithEpochState(epochState{})), WithMetaBaseOptions(meta.WithPath(filepath.Join(dir, "meta_new")), meta.WithEpochState(epochState{})),
@ -155,7 +157,7 @@ func TestRefillMetabaseCorrupted(t *testing.T) {
var getPrm GetPrm var getPrm GetPrm
getPrm.SetAddress(addr) getPrm.SetAddress(addr)
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
require.NoError(t, sh.Close()) require.NoError(t, sh.Close())
} }
@ -176,6 +178,7 @@ func TestRefillMetabase(t *testing.T) {
} }
sh := New( sh := New(
WithID(NewIDFromBytes([]byte{})),
WithBlobStorOptions(blobOpts...), WithBlobStorOptions(blobOpts...),
WithMetaBaseOptions( WithMetaBaseOptions(
meta.WithPath(filepath.Join(p, "meta")), meta.WithPath(filepath.Join(p, "meta")),
@ -277,7 +280,7 @@ func TestRefillMetabase(t *testing.T) {
checkObj := func(addr oid.Address, expObj *objectSDK.Object) { checkObj := func(addr oid.Address, expObj *objectSDK.Object) {
headPrm.SetAddress(addr) headPrm.SetAddress(addr)
res, err := sh.Head(headPrm) res, err := sh.Head(context.Background(), headPrm)
if expObj == nil { if expObj == nil {
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
@ -302,7 +305,7 @@ func TestRefillMetabase(t *testing.T) {
for _, member := range tombMembers { for _, member := range tombMembers {
headPrm.SetAddress(member) headPrm.SetAddress(member)
_, err := sh.Head(headPrm) _, err := sh.Head(context.Background(), headPrm)
if exists { if exists {
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved)) require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
@ -343,6 +346,7 @@ func TestRefillMetabase(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
sh = New( sh = New(
WithID(NewIDFromBytes([]byte{})),
WithBlobStorOptions(blobOpts...), WithBlobStorOptions(blobOpts...),
WithMetaBaseOptions( WithMetaBaseOptions(
meta.WithPath(filepath.Join(p, "meta_restored")), meta.WithPath(filepath.Join(p, "meta_restored")),

View file

@ -1,6 +1,7 @@
package shard_test package shard_test
import ( import (
"context"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
@ -51,7 +52,7 @@ func testShardDelete(t *testing.T, hasWriteCache bool) {
_, err = sh.Delete(delPrm) _, err = sh.Delete(delPrm)
require.NoError(t, err) require.NoError(t, err)
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
@ -69,13 +70,13 @@ func testShardDelete(t *testing.T, hasWriteCache bool) {
_, err := sh.Put(putPrm) _, err := sh.Put(putPrm)
require.NoError(t, err) require.NoError(t, err)
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.NoError(t, err) require.NoError(t, err)
_, err = sh.Delete(delPrm) _, err = sh.Delete(delPrm)
require.NoError(t, err) require.NoError(t, err)
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
} }

View file

@ -2,6 +2,7 @@ package shard_test
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"math/rand" "math/rand"
"os" "os"
@ -276,7 +277,7 @@ func checkRestore(t *testing.T, sh *shard.Shard, prm shard.RestorePrm, objects [
for i := range objects { for i := range objects {
getPrm.SetAddress(object.AddressOf(objects[i])) getPrm.SetAddress(object.AddressOf(objects[i]))
res, err := sh.Get(getPrm) res, err := sh.Get(context.Background(), getPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[i], res.Object()) require.Equal(t, objects[i], res.Object())
} }

View file

@ -1,6 +1,8 @@
package shard package shard
import ( import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase" meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@ -33,7 +35,7 @@ func (p ExistsRes) Exists() bool {
// //
// Returns an error of type apistatus.ObjectAlreadyRemoved if object has been marked as removed. // Returns an error of type apistatus.ObjectAlreadyRemoved if object has been marked as removed.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired. // Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) Exists(prm ExistsPrm) (ExistsRes, error) { func (s *Shard) Exists(ctx context.Context, prm ExistsPrm) (ExistsRes, error) {
var exists bool var exists bool
var err error var err error
@ -45,7 +47,7 @@ func (s *Shard) Exists(prm ExistsPrm) (ExistsRes, error) {
p.Address = prm.addr p.Address = prm.addr
var res common.ExistsRes var res common.ExistsRes
res, err = s.blobStor.Exists(p) res, err = s.blobStor.Exists(ctx, p)
exists = res.Exists exists = res.Exists
} else { } else {
var existsPrm meta.ExistsPrm var existsPrm meta.ExistsPrm

View file

@ -33,6 +33,7 @@ func Test_GCDropsLockedExpiredObject(t *testing.T) {
rootPath := t.TempDir() rootPath := t.TempDir()
opts := []shard.Option{ opts := []shard.Option{
shard.WithID(shard.NewIDFromBytes([]byte{})),
shard.WithLogger(&logger.Logger{Logger: zap.NewNop()}), shard.WithLogger(&logger.Logger{Logger: zap.NewNop()}),
shard.WithBlobStorOptions( shard.WithBlobStorOptions(
blobstor.WithStorages([]blobstor.SubStorage{ blobstor.WithStorages([]blobstor.SubStorage{
@ -115,7 +116,7 @@ func Test_GCDropsLockedExpiredObject(t *testing.T) {
var getPrm shard.GetPrm var getPrm shard.GetPrm
getPrm.SetAddress(objectCore.AddressOf(obj)) getPrm.SetAddress(objectCore.AddressOf(obj))
require.Eventually(t, func() bool { require.Eventually(t, func() bool {
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
return shard.IsErrNotFound(err) return shard.IsErrNotFound(err)
}, 3*time.Second, 1*time.Second, "expired object must be deleted") }, 3*time.Second, 1*time.Second, "expired object must be deleted")
} }

View file

@ -1,8 +1,10 @@
package shard package shard
import ( import (
"context"
"fmt" "fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase" meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
@ -11,6 +13,8 @@ import (
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -61,7 +65,15 @@ func (r GetRes) HasMeta() bool {
// Returns an error of type apistatus.ObjectNotFound if the requested object is missing in shard. // Returns an error of type apistatus.ObjectNotFound if the requested object is missing in shard.
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard. // Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired. // Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) Get(prm GetPrm) (GetRes, error) { func (s *Shard) Get(ctx context.Context, prm GetPrm) (GetRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Shard.Get",
trace.WithAttributes(
attribute.String("shard_id", s.ID().String()),
attribute.String("address", prm.addr.EncodeToString()),
attribute.Bool("skip_meta", prm.skipMeta),
))
defer span.End()
s.m.RLock() s.m.RLock()
defer s.m.RUnlock() defer s.m.RUnlock()
@ -70,7 +82,7 @@ func (s *Shard) Get(prm GetPrm) (GetRes, error) {
getPrm.Address = prm.addr getPrm.Address = prm.addr
getPrm.StorageID = id getPrm.StorageID = id
res, err := stor.Get(getPrm) res, err := stor.Get(ctx, getPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,7 +91,7 @@ func (s *Shard) Get(prm GetPrm) (GetRes, error) {
} }
wc := func(c writecache.Cache) (*objectSDK.Object, error) { wc := func(c writecache.Cache) (*objectSDK.Object, error) {
return c.Get(prm.addr) return c.Get(ctx, prm.addr)
} }
skipMeta := prm.skipMeta || s.info.Mode.NoMetabase() skipMeta := prm.skipMeta || s.info.Mode.NoMetabase()

View file

@ -2,6 +2,7 @@ package shard_test
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"testing" "testing"
"time" "time"
@ -111,11 +112,11 @@ func testShardGet(t *testing.T, hasWriteCache bool) {
} }
func testGet(t *testing.T, sh *shard.Shard, getPrm shard.GetPrm, hasWriteCache bool) (shard.GetRes, error) { func testGet(t *testing.T, sh *shard.Shard, getPrm shard.GetPrm, hasWriteCache bool) (shard.GetRes, error) {
res, err := sh.Get(getPrm) res, err := sh.Get(context.Background(), getPrm)
if hasWriteCache { if hasWriteCache {
require.Eventually(t, func() bool { require.Eventually(t, func() bool {
if shard.IsErrNotFound(err) { if shard.IsErrNotFound(err) {
res, err = sh.Get(getPrm) res, err = sh.Get(context.Background(), getPrm)
} }
return !shard.IsErrNotFound(err) return !shard.IsErrNotFound(err)
}, time.Second, time.Millisecond*100) }, time.Second, time.Millisecond*100)

View file

@ -1,9 +1,14 @@
package shard package shard
import ( import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase" meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// HeadPrm groups the parameters of Head operation. // HeadPrm groups the parameters of Head operation.
@ -43,7 +48,15 @@ func (r HeadRes) Object() *objectSDK.Object {
// Returns an error of type apistatus.ObjectNotFound if object is missing in Shard. // Returns an error of type apistatus.ObjectNotFound if object is missing in Shard.
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard. // Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired. // Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) Head(prm HeadPrm) (HeadRes, error) { func (s *Shard) Head(ctx context.Context, prm HeadPrm) (HeadRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Shard.Head",
trace.WithAttributes(
attribute.String("shard_id", s.ID().String()),
attribute.String("address", prm.addr.EncodeToString()),
attribute.Bool("raw", prm.raw),
))
defer span.End()
var obj *objectSDK.Object var obj *objectSDK.Object
var err error var err error
if s.GetMode().NoMetabase() { if s.GetMode().NoMetabase() {
@ -52,7 +65,7 @@ func (s *Shard) Head(prm HeadPrm) (HeadRes, error) {
getPrm.SetIgnoreMeta(true) getPrm.SetIgnoreMeta(true)
var res GetRes var res GetRes
res, err = s.Get(getPrm) res, err = s.Get(ctx, getPrm)
obj = res.Object() obj = res.Object()
} else { } else {
var headParams meta.GetPrm var headParams meta.GetPrm

View file

@ -1,6 +1,7 @@
package shard_test package shard_test
import ( import (
"context"
"errors" "errors"
"testing" "testing"
"time" "time"
@ -75,18 +76,18 @@ func testShardHead(t *testing.T, hasWriteCache bool) {
headPrm.SetAddress(object.AddressOf(parent)) headPrm.SetAddress(object.AddressOf(parent))
headPrm.SetRaw(false) headPrm.SetRaw(false)
head, err := sh.Head(headPrm) head, err := sh.Head(context.Background(), headPrm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, parent.CutPayload(), head.Object()) require.Equal(t, parent.CutPayload(), head.Object())
}) })
} }
func testHead(t *testing.T, sh *shard.Shard, headPrm shard.HeadPrm, hasWriteCache bool) (shard.HeadRes, error) { func testHead(t *testing.T, sh *shard.Shard, headPrm shard.HeadPrm, hasWriteCache bool) (shard.HeadRes, error) {
res, err := sh.Head(headPrm) res, err := sh.Head(context.Background(), headPrm)
if hasWriteCache { if hasWriteCache {
require.Eventually(t, func() bool { require.Eventually(t, func() bool {
if shard.IsErrNotFound(err) { if shard.IsErrNotFound(err) {
res, err = sh.Head(headPrm) res, err = sh.Head(context.Background(), headPrm)
} }
return !shard.IsErrNotFound(err) return !shard.IsErrNotFound(err)
}, time.Second, time.Millisecond*100) }, time.Second, time.Millisecond*100)

View file

@ -51,6 +51,6 @@ func testShardInhume(t *testing.T, hasWriteCache bool) {
_, err = sh.Inhume(context.Background(), inhPrm) _, err = sh.Inhume(context.Background(), inhPrm)
require.NoError(t, err) require.NoError(t, err)
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved)) require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
} }

View file

@ -27,6 +27,7 @@ func TestShard_Lock(t *testing.T) {
rootPath := t.TempDir() rootPath := t.TempDir()
opts := []shard.Option{ opts := []shard.Option{
shard.WithID(shard.NewIDFromBytes([]byte{})),
shard.WithLogger(&logger.Logger{Logger: zap.NewNop()}), shard.WithLogger(&logger.Logger{Logger: zap.NewNop()}),
shard.WithBlobStorOptions( shard.WithBlobStorOptions(
blobstor.WithStorages([]blobstor.SubStorage{ blobstor.WithStorages([]blobstor.SubStorage{
@ -137,7 +138,7 @@ func TestShard_Lock(t *testing.T) {
var getPrm shard.GetPrm var getPrm shard.GetPrm
getPrm.SetAddress(objectcore.AddressOf(obj)) getPrm.SetAddress(objectcore.AddressOf(obj))
_, err = sh.Get(getPrm) _, err = sh.Get(context.Background(), getPrm)
require.ErrorAs(t, err, new(apistatus.ObjectNotFound)) require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
}) })
} }

View file

@ -1,6 +1,10 @@
package shard package shard
import ( import (
"context"
"strconv"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
@ -8,6 +12,8 @@ import (
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// RngPrm groups the parameters of GetRange operation. // RngPrm groups the parameters of GetRange operation.
@ -66,7 +72,17 @@ func (r RngRes) HasMeta() bool {
// Returns an error of type apistatus.ObjectNotFound if the requested object is missing. // Returns an error of type apistatus.ObjectNotFound if the requested object is missing.
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard. // Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired. // Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) GetRange(prm RngPrm) (RngRes, error) { func (s *Shard) GetRange(ctx context.Context, prm RngPrm) (RngRes, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "Shard.GetRange",
trace.WithAttributes(
attribute.String("shard_id", s.ID().String()),
attribute.String("address", prm.addr.EncodeToString()),
attribute.Bool("skip_meta", prm.skipMeta),
attribute.String("offset", strconv.FormatUint(prm.off, 10)),
attribute.String("length", strconv.FormatUint(prm.ln, 10)),
))
defer span.End()
s.m.RLock() s.m.RLock()
defer s.m.RUnlock() defer s.m.RUnlock()
@ -77,7 +93,7 @@ func (s *Shard) GetRange(prm RngPrm) (RngRes, error) {
getRngPrm.Range.SetLength(prm.ln) getRngPrm.Range.SetLength(prm.ln)
getRngPrm.StorageID = id getRngPrm.StorageID = id
res, err := stor.GetRange(getRngPrm) res, err := stor.GetRange(ctx, getRngPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +105,7 @@ func (s *Shard) GetRange(prm RngPrm) (RngRes, error) {
} }
wc := func(c writecache.Cache) (*object.Object, error) { wc := func(c writecache.Cache) (*object.Object, error) {
res, err := c.Get(prm.addr) res, err := c.Get(ctx, prm.addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,6 +1,7 @@
package shard_test package shard_test
import ( import (
"context"
"math" "math"
"path/filepath" "path/filepath"
"testing" "testing"
@ -105,7 +106,7 @@ func testShardGetRange(t *testing.T, hasWriteCache bool) {
rngPrm.SetAddress(addr) rngPrm.SetAddress(addr)
rngPrm.SetRange(tc.rng.GetOffset(), tc.rng.GetLength()) rngPrm.SetRange(tc.rng.GetOffset(), tc.rng.GetLength())
res, err := sh.GetRange(rngPrm) res, err := sh.GetRange(context.Background(), rngPrm)
if tc.hasErr { if tc.hasErr {
require.ErrorAs(t, err, &apistatus.ObjectOutOfRange{}) require.ErrorAs(t, err, &apistatus.ObjectOutOfRange{})
} else { } else {

View file

@ -66,7 +66,7 @@ func TestShardReload(t *testing.T) {
var prm ExistsPrm var prm ExistsPrm
prm.SetAddress(objects[i].addr) prm.SetAddress(objects[i].addr)
res, err := sh.Exists(prm) res, err := sh.Exists(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, exists, res.Exists(), "object #%d is missing", i) require.Equal(t, exists, res.Exists(), "object #%d is missing", i)
} }

View file

@ -63,6 +63,7 @@ func newCustomShard(t testing.TB, rootPath string, enableWriteCache bool, wcOpts
} }
opts := []shard.Option{ opts := []shard.Option{
shard.WithID(shard.NewIDFromBytes([]byte{})),
shard.WithLogger(&logger.Logger{Logger: zap.L()}), shard.WithLogger(&logger.Logger{Logger: zap.L()}),
shard.WithBlobStorOptions(bsOpts...), shard.WithBlobStorOptions(bsOpts...),
shard.WithMetaBaseOptions( shard.WithMetaBaseOptions(

View file

@ -1,6 +1,7 @@
package shard_test package shard_test
import ( import (
"context"
"math/rand" "math/rand"
"testing" "testing"
@ -55,7 +56,7 @@ func TestWriteCacheObjectLoss(t *testing.T) {
for i := range objects { for i := range objects {
getPrm.SetAddress(object.AddressOf(objects[i])) getPrm.SetAddress(object.AddressOf(objects[i]))
_, err := sh.Get(getPrm) _, err := sh.Get(context.Background(), getPrm)
require.NoError(t, err, i) require.NoError(t, err, i)
} }
} }

View file

@ -1,6 +1,7 @@
package writecache package writecache
import ( import (
"context"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -95,7 +96,7 @@ func TestFlush(t *testing.T) {
prm.Address = objects[i].addr prm.Address = objects[i].addr
prm.StorageID = mRes.StorageID() prm.StorageID = mRes.StorageID()
res, err := bs.Get(prm) res, err := bs.Get(context.Background(), prm)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, objects[i].obj, res.Object) require.Equal(t, objects[i].obj, res.Object)
} }
@ -119,7 +120,7 @@ func TestFlush(t *testing.T) {
_, err := mb.Get(mPrm) _, err := mb.Get(mPrm)
require.Error(t, err) require.Error(t, err)
_, err = bs.Get(common.GetPrm{Address: objects[i].addr}) _, err = bs.Get(context.Background(), common.GetPrm{Address: objects[i].addr})
require.Error(t, err) require.Error(t, err)
} }
@ -149,7 +150,7 @@ func TestFlush(t *testing.T) {
_, err := mb.Get(mPrm) _, err := mb.Get(mPrm)
require.Error(t, err) require.Error(t, err)
_, err = bs.Get(common.GetPrm{Address: objects[i].addr}) _, err = bs.Get(context.Background(), common.GetPrm{Address: objects[i].addr})
require.Error(t, err) require.Error(t, err)
} }
@ -266,7 +267,7 @@ func TestFlush(t *testing.T) {
require.NoError(t, wc.Open(true)) require.NoError(t, wc.Open(true))
initWC(t, wc) initWC(t, wc)
for i := range objects { for i := range objects {
_, err := wc.Get(objects[i].addr) _, err := wc.Get(context.Background(), objects[i].addr)
require.NoError(t, err, i) require.NoError(t, err, i)
} }
require.NoError(t, wc.Close()) require.NoError(t, wc.Close())
@ -275,7 +276,7 @@ func TestFlush(t *testing.T) {
require.NoError(t, wc.Open(false)) require.NoError(t, wc.Open(false))
initWC(t, wc) initWC(t, wc)
for i := range objects { for i := range objects {
_, err := wc.Get(objects[i].addr) _, err := wc.Get(context.Background(), objects[i].addr)
if i < 2 { if i < 2 {
require.ErrorAs(t, err, new(apistatus.ObjectNotFound), i) require.ErrorAs(t, err, new(apistatus.ObjectNotFound), i)
} else { } else {

View file

@ -1,6 +1,9 @@
package writecache package writecache
import ( import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -8,14 +11,22 @@ import (
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/nspcc-dev/neo-go/pkg/util/slice"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
// Get returns object from write-cache. // Get returns object from write-cache.
// //
// Returns an error of type apistatus.ObjectNotFound if the requested object is missing in write-cache. // Returns an error of type apistatus.ObjectNotFound if the requested object is missing in write-cache.
func (c *cache) Get(addr oid.Address) (*objectSDK.Object, error) { func (c *cache) Get(ctx context.Context, addr oid.Address) (*objectSDK.Object, error) {
saddr := addr.EncodeToString() saddr := addr.EncodeToString()
ctx, span := tracing.StartSpanFromContext(ctx, "writecache.Get",
trace.WithAttributes(
attribute.String("address", saddr),
))
defer span.End()
value, err := Get(c.db, []byte(saddr)) value, err := Get(c.db, []byte(saddr))
if err == nil { if err == nil {
obj := objectSDK.New() obj := objectSDK.New()
@ -23,7 +34,7 @@ func (c *cache) Get(addr oid.Address) (*objectSDK.Object, error) {
return obj, obj.Unmarshal(value) return obj, obj.Unmarshal(value)
} }
res, err := c.fsTree.Get(common.GetPrm{Address: addr}) res, err := c.fsTree.Get(ctx, common.GetPrm{Address: addr})
if err != nil { if err != nil {
return nil, logicerr.Wrap(apistatus.ObjectNotFound{}) return nil, logicerr.Wrap(apistatus.ObjectNotFound{})
} }
@ -35,8 +46,14 @@ func (c *cache) Get(addr oid.Address) (*objectSDK.Object, error) {
// Head returns object header from write-cache. // Head returns object header from write-cache.
// //
// Returns an error of type apistatus.ObjectNotFound if the requested object is missing in write-cache. // Returns an error of type apistatus.ObjectNotFound if the requested object is missing in write-cache.
func (c *cache) Head(addr oid.Address) (*objectSDK.Object, error) { func (c *cache) Head(ctx context.Context, addr oid.Address) (*objectSDK.Object, error) {
obj, err := c.Get(addr) ctx, span := tracing.StartSpanFromContext(ctx, "writecache.Head",
trace.WithAttributes(
attribute.String("address", addr.EncodeToString()),
))
defer span.End()
obj, err := c.Get(ctx, addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,6 +1,7 @@
package writecache package writecache
import ( import (
"context"
"errors" "errors"
"sync" "sync"
@ -177,6 +178,6 @@ func (c *cache) flushStatus(addr oid.Address) (bool, bool) {
prm.SetAddress(addr) prm.SetAddress(addr)
mRes, _ := c.metabase.StorageID(prm) mRes, _ := c.metabase.StorageID(prm)
res, err := c.blobstor.Exists(common.ExistsPrm{Address: addr, StorageID: mRes.StorageID()}) res, err := c.blobstor.Exists(context.TODO(), common.ExistsPrm{Address: addr, StorageID: mRes.StorageID()})
return err == nil && res.Exists, false return err == nil && res.Exists, false
} }

View file

@ -1,6 +1,7 @@
package writecache package writecache
import ( import (
"context"
"io/fs" "io/fs"
"os" "os"
"time" "time"
@ -27,7 +28,7 @@ type metabase interface {
type blob interface { type blob interface {
Put(common.PutPrm) (common.PutRes, error) Put(common.PutPrm) (common.PutRes, error)
NeedsCompression(obj *objectSDK.Object) bool NeedsCompression(obj *objectSDK.Object) bool
Exists(res common.ExistsPrm) (common.ExistsRes, error) Exists(ctx context.Context, res common.ExistsPrm) (common.ExistsRes, error)
} }
type options struct { type options struct {

View file

@ -1,6 +1,7 @@
package writecache package writecache
import ( import (
"context"
"os" "os"
"sync" "sync"
@ -23,8 +24,8 @@ type Info struct {
// Cache represents write-cache for objects. // Cache represents write-cache for objects.
type Cache interface { type Cache interface {
Get(address oid.Address) (*object.Object, error) Get(ctx context.Context, address oid.Address) (*object.Object, error)
Head(oid.Address) (*object.Object, error) Head(context.Context, oid.Address) (*object.Object, error)
// Delete removes object referenced by the given oid.Address from the // Delete removes object referenced by the given oid.Address from the
// Cache. Returns any error encountered that prevented the object to be // Cache. Returns any error encountered that prevented the object to be
// removed. // removed.

View file

@ -19,7 +19,7 @@ import (
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
) )
func (s *Server) EvacuateShard(_ context.Context, req *control.EvacuateShardRequest) (*control.EvacuateShardResponse, error) { func (s *Server) EvacuateShard(ctx context.Context, req *control.EvacuateShardRequest) (*control.EvacuateShardResponse, error) {
err := s.isValidRequest(req) err := s.isValidRequest(req)
if err != nil { if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error()) return nil, status.Error(codes.PermissionDenied, err.Error())
@ -30,7 +30,7 @@ func (s *Server) EvacuateShard(_ context.Context, req *control.EvacuateShardRequ
prm.WithIgnoreErrors(req.GetBody().GetIgnoreErrors()) prm.WithIgnoreErrors(req.GetBody().GetIgnoreErrors())
prm.WithFaultHandler(s.replicate) prm.WithFaultHandler(s.replicate)
res, err := s.s.Evacuate(prm) res, err := s.s.Evacuate(ctx, prm)
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, err.Error()) return nil, status.Error(codes.Internal, err.Error())
} }

View file

@ -1,6 +1,8 @@
package notificator package notificator
import ( import (
"context"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
) )
@ -8,7 +10,7 @@ import (
type NotificationSource interface { type NotificationSource interface {
// Iterate must iterate over all notifications for the // Iterate must iterate over all notifications for the
// provided epoch and call handler for all of them. // provided epoch and call handler for all of them.
Iterate(epoch uint64, handler func(topic string, addr oid.Address)) Iterate(ctx context.Context, epoch uint64, handler func(topic string, addr oid.Address))
} }
// NotificationWriter notifies all the subscribers // NotificationWriter notifies all the subscribers

View file

@ -1,6 +1,7 @@
package notificator package notificator
import ( import (
"context"
"fmt" "fmt"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
@ -71,11 +72,11 @@ func New(prm *Prm) *Notificator {
// ProcessEpoch looks for all objects with defined epoch in the storage // ProcessEpoch looks for all objects with defined epoch in the storage
// and passes their addresses to the NotificationWriter. // and passes their addresses to the NotificationWriter.
func (n *Notificator) ProcessEpoch(epoch uint64) { func (n *Notificator) ProcessEpoch(ctx context.Context, epoch uint64) {
logger := n.l.With(zap.Uint64("epoch", epoch)) logger := n.l.With(zap.Uint64("epoch", epoch))
logger.Debug("notificator: start processing object notifications") logger.Debug("notificator: start processing object notifications")
n.ns.Iterate(epoch, func(topic string, addr oid.Address) { n.ns.Iterate(ctx, epoch, func(topic string, addr oid.Address) {
n.l.Debug("notificator: processing object notification", n.l.Debug("notificator: processing object notification",
zap.String("topic", topic), zap.String("topic", topic),
zap.Stringer("address", addr), zap.Stringer("address", addr),

View file

@ -1,6 +1,7 @@
package v2 package v2
import ( import (
"context"
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
"testing" "testing"
@ -26,7 +27,7 @@ type testLocalStorage struct {
err error err error
} }
func (s *testLocalStorage) Head(addr oid.Address) (*object.Object, error) { func (s *testLocalStorage) Head(ctx context.Context, addr oid.Address) (*object.Object, error) {
require.True(s.t, addr.Container().Equals(s.expAddr.Container())) require.True(s.t, addr.Container().Equals(s.expAddr.Container()))
require.True(s.t, addr.Object().Equals(s.expAddr.Object())) require.True(s.t, addr.Object().Equals(s.expAddr.Object()))

View file

@ -1,6 +1,7 @@
package v2 package v2
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
@ -27,7 +28,7 @@ type cfg struct {
} }
type ObjectStorage interface { type ObjectStorage interface {
Head(oid.Address) (*object.Object, error) Head(context.Context, oid.Address) (*object.Object, error)
} }
type Request interface { type Request interface {
@ -207,7 +208,7 @@ func (h *cfg) localObjectHeaders(cnr cid.ID, idObj *oid.ID) ([]eaclSDK.Header, b
addr.SetContainer(cnr) addr.SetContainer(cnr)
addr.SetObject(*idObj) addr.SetObject(*idObj)
obj, err := h.storage.Head(addr) obj, err := h.storage.Head(context.TODO(), addr)
if err == nil { if err == nil {
return headersFromObject(obj, cnr, idObj), true return headersFromObject(obj, cnr, idObj), true
} }

View file

@ -1,6 +1,7 @@
package v2 package v2
import ( import (
"context"
"io" "io"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine"
@ -12,10 +13,10 @@ type localStorage struct {
ls *engine.StorageEngine ls *engine.StorageEngine
} }
func (s *localStorage) Head(addr oid.Address) (*objectSDK.Object, error) { func (s *localStorage) Head(ctx context.Context, addr oid.Address) (*objectSDK.Object, error) {
if s.ls == nil { if s.ls == nil {
return nil, io.ErrUnexpectedEOF return nil, io.ErrUnexpectedEOF
} }
return engine.Head(s.ls, addr) return engine.Head(ctx, s.ls, addr)
} }

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object"
@ -111,6 +112,14 @@ func New(opts ...Option) Service {
// Get implements ServiceServer interface, makes ACL checks and calls // Get implements ServiceServer interface, makes ACL checks and calls
// next Get method in the ServiceServer pipeline. // next Get method in the ServiceServer pipeline.
func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream) error { func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream) error {
spanClosed := false
_, span := tracing.StartSpanFromContext(stream.Context(), "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
cnr, err := getContainerIDFromRequest(request) cnr, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return err return err
@ -158,6 +167,9 @@ func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream
return eACLErr(reqInfo, err) return eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
return b.next.Get(request, &getStreamBasicChecker{ return b.next.Get(request, &getStreamBasicChecker{
GetObjectStream: stream, GetObjectStream: stream,
info: reqInfo, info: reqInfo,
@ -177,6 +189,14 @@ func (b Service) Put() (object.PutObjectStream, error) {
func (b Service) Head( func (b Service) Head(
ctx context.Context, ctx context.Context,
request *objectV2.HeadRequest) (*objectV2.HeadResponse, error) { request *objectV2.HeadRequest) (*objectV2.HeadResponse, error) {
spanClosed := false
_, span := tracing.StartSpanFromContext(ctx, "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
cnr, err := getContainerIDFromRequest(request) cnr, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return nil, err return nil, err
@ -224,6 +244,9 @@ func (b Service) Head(
return nil, eACLErr(reqInfo, err) return nil, eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
resp, err := b.next.Head(ctx, request) resp, err := b.next.Head(ctx, request)
if err == nil { if err == nil {
if err = b.checker.CheckEACL(resp, reqInfo); err != nil { if err = b.checker.CheckEACL(resp, reqInfo); err != nil {
@ -235,6 +258,14 @@ func (b Service) Head(
} }
func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStream) error { func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStream) error {
spanClosed := false
_, span := tracing.StartSpanFromContext(stream.Context(), "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
id, err := getContainerIDFromRequest(request) id, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return err return err
@ -275,6 +306,9 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
return eACLErr(reqInfo, err) return eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
return b.next.Search(request, &searchStreamBasicChecker{ return b.next.Search(request, &searchStreamBasicChecker{
checker: b.checker, checker: b.checker,
SearchStream: stream, SearchStream: stream,
@ -285,6 +319,14 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
func (b Service) Delete( func (b Service) Delete(
ctx context.Context, ctx context.Context,
request *objectV2.DeleteRequest) (*objectV2.DeleteResponse, error) { request *objectV2.DeleteRequest) (*objectV2.DeleteResponse, error) {
spanClosed := false
_, span := tracing.StartSpanFromContext(ctx, "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
cnr, err := getContainerIDFromRequest(request) cnr, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return nil, err return nil, err
@ -332,10 +374,21 @@ func (b Service) Delete(
return nil, eACLErr(reqInfo, err) return nil, eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
return b.next.Delete(ctx, request) return b.next.Delete(ctx, request)
} }
func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetObjectRangeStream) error { func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetObjectRangeStream) error {
spanClosed := false
_, span := tracing.StartSpanFromContext(stream.Context(), "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
cnr, err := getContainerIDFromRequest(request) cnr, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return err return err
@ -383,6 +436,9 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
return eACLErr(reqInfo, err) return eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
return b.next.GetRange(request, &rangeStreamBasicChecker{ return b.next.GetRange(request, &rangeStreamBasicChecker{
checker: b.checker, checker: b.checker,
GetObjectRangeStream: stream, GetObjectRangeStream: stream,
@ -393,6 +449,14 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
func (b Service) GetRangeHash( func (b Service) GetRangeHash(
ctx context.Context, ctx context.Context,
request *objectV2.GetRangeHashRequest) (*objectV2.GetRangeHashResponse, error) { request *objectV2.GetRangeHashRequest) (*objectV2.GetRangeHashResponse, error) {
spanClosed := false
_, span := tracing.StartSpanFromContext(ctx, "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
cnr, err := getContainerIDFromRequest(request) cnr, err := getContainerIDFromRequest(request)
if err != nil { if err != nil {
return nil, err return nil, err
@ -440,10 +504,21 @@ func (b Service) GetRangeHash(
return nil, eACLErr(reqInfo, err) return nil, eACLErr(reqInfo, err)
} }
span.End()
spanClosed = true
return b.next.GetRangeHash(ctx, request) return b.next.GetRangeHash(ctx, request)
} }
func (p putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutRequest) error { func (p putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutRequest) error {
spanClosed := false
_, span := tracing.StartSpanFromContext(ctx, "checkACL")
defer func() {
if !spanClosed {
span.End()
}
}()
body := request.GetBody() body := request.GetBody()
if body == nil { if body == nil {
return errEmptyBody return errEmptyBody
@ -512,6 +587,9 @@ func (p putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutRe
} }
} }
span.End()
spanClosed = true
return p.next.Send(ctx, request) return p.next.Send(ctx, request)
} }

View file

@ -139,7 +139,7 @@ func (c *testClient) addResult(addr oid.Address, obj *objectSDK.Object, err erro
}{obj: obj, err: err} }{obj: obj, err: err}
} }
func (s *testStorage) get(exec *execCtx) (*objectSDK.Object, error) { func (s *testStorage) get(_ context.Context, exec *execCtx) (*objectSDK.Object, error) {
var ( var (
ok bool ok bool
obj *objectSDK.Object obj *objectSDK.Object

View file

@ -4,15 +4,21 @@ import (
"context" "context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.uber.org/zap" "go.uber.org/zap"
) )
func (exec *execCtx) executeLocal(ctx context.Context) { func (exec *execCtx) executeLocal(ctx context.Context) {
ctx, span := tracing.StartSpanFromContext(ctx, "getService.executeLocal")
defer func() {
span.End()
}()
var err error var err error
exec.collectedObject, err = exec.svc.localStorage.get(exec) exec.collectedObject, err = exec.svc.localStorage.get(ctx, exec)
var errSplitInfo *objectSDK.SplitInfoError var errSplitInfo *objectSDK.SplitInfoError
var errRemoved apistatus.ObjectAlreadyRemoved var errRemoved apistatus.ObjectAlreadyRemoved

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -11,6 +12,9 @@ import (
) )
func (exec *execCtx) processNode(ctx context.Context, info client.NodeInfo) bool { func (exec *execCtx) processNode(ctx context.Context, info client.NodeInfo) bool {
ctx, span := tracing.StartSpanFromContext(ctx, "getService.processNode")
defer span.End()
exec.log.Debug("processing node...") exec.log.Debug("processing node...")
client, ok := exec.remoteClient(info) client, ok := exec.remoteClient(info)

View file

@ -31,7 +31,7 @@ type cfg struct {
log *logger.Logger log *logger.Logger
localStorage interface { localStorage interface {
get(*execCtx) (*object.Object, error) get(context.Context, *execCtx) (*object.Object, error)
} }
clientCache interface { clientCache interface {

View file

@ -200,13 +200,13 @@ func (c *clientWrapper) get(ctx context.Context, exec *execCtx, key *ecdsa.Priva
return res.Object(), nil return res.Object(), nil
} }
func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, error) { func (e *storageEngineWrapper) get(ctx context.Context, exec *execCtx) (*object.Object, error) {
if exec.headOnly() { if exec.headOnly() {
var headPrm engine.HeadPrm var headPrm engine.HeadPrm
headPrm.WithAddress(exec.address()) headPrm.WithAddress(exec.address())
headPrm.WithRaw(exec.isRaw()) headPrm.WithRaw(exec.isRaw())
r, err := e.engine.Head(headPrm) r, err := e.engine.Head(ctx, headPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -217,7 +217,7 @@ func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, error) {
getRange.WithAddress(exec.address()) getRange.WithAddress(exec.address())
getRange.WithPayloadRange(rng) getRange.WithPayloadRange(rng)
r, err := e.engine.GetRange(getRange) r, err := e.engine.GetRange(ctx, getRange)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -227,7 +227,7 @@ func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, error) {
var getPrm engine.GetPrm var getPrm engine.GetPrm
getPrm.WithAddress(exec.address()) getPrm.WithAddress(exec.address())
r, err := e.engine.Get(getPrm) r, err := e.engine.Get(ctx, getPrm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -9,6 +9,7 @@ import (
"sync" "sync"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
@ -18,6 +19,8 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal"
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
type getRequestForwarder struct { type getRequestForwarder struct {
@ -30,6 +33,11 @@ type getRequestForwarder struct {
} }
func (f *getRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) { func (f *getRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "getRequestForwarder.forwardRequestToNode",
trace.WithAttributes(attribute.String("address", addr.String())),
)
defer span.End()
var err error var err error
// once compose and resign forwarding request // once compose and resign forwarding request

View file

@ -9,6 +9,7 @@ import (
"sync" "sync"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
@ -18,6 +19,8 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal"
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
type getRangeRequestForwarder struct { type getRangeRequestForwarder struct {
@ -29,6 +32,11 @@ type getRangeRequestForwarder struct {
} }
func (f *getRangeRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) { func (f *getRangeRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "getRangeRequestForwarder.forwardRequestToNode",
trace.WithAttributes(attribute.String("address", addr.String())),
)
defer span.End()
var err error var err error
// once compose and resign forwarding request // once compose and resign forwarding request

View file

@ -8,6 +8,7 @@ import (
"sync" "sync"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
@ -19,6 +20,8 @@ import (
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
) )
type headRequestForwarder struct { type headRequestForwarder struct {
@ -30,6 +33,11 @@ type headRequestForwarder struct {
} }
func (f *headRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) { func (f *headRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
ctx, span := tracing.StartSpanFromContext(ctx, "headRequestForwarder.forwardRequestToNode",
trace.WithAttributes(attribute.String("address", addr.String())),
)
defer span.End()
var err error var err error
// once compose and resign forwarding request // once compose and resign forwarding request

View file

@ -96,7 +96,7 @@ func (s *Service) Head(ctx context.Context, req *objectV2.HeadRequest) (*objectV
resp := new(objectV2.HeadResponse) resp := new(objectV2.HeadResponse)
resp.SetBody(new(objectV2.HeadResponseBody)) resp.SetBody(new(objectV2.HeadResponseBody))
p, err := s.toHeadPrm(ctx, req, resp) p, err := s.toHeadPrm(req, resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -215,7 +215,7 @@ func (w *headResponseWriter) WriteHeader(_ context.Context, hdr *object.Object)
return nil return nil
} }
func (s *Service) toHeadPrm(ctx context.Context, req *objectV2.HeadRequest, resp *objectV2.HeadResponse) (*getsvc.HeadPrm, error) { func (s *Service) toHeadPrm(req *objectV2.HeadRequest, resp *objectV2.HeadResponse) (*getsvc.HeadPrm, error) {
body := req.GetBody() body := req.GetBody()
addrV2 := body.GetAddress() addrV2 := body.GetAddress()

View file

@ -54,7 +54,7 @@ func (s *getStreamSigner) Send(resp *object.GetResponse) error {
} }
func (s *SignService) Get(req *object.GetRequest, stream GetObjectStream) error { func (s *SignService) Get(req *object.GetRequest, stream GetObjectStream) error {
return s.sigSvc.HandleServerStreamRequest(req, return s.sigSvc.HandleServerStreamRequest(stream.Context(), req,
func(resp util.ResponseMessage) error { func(resp util.ResponseMessage) error {
return stream.Send(resp.(*object.GetResponse)) return stream.Send(resp.(*object.GetResponse))
}, },
@ -126,7 +126,7 @@ func (s *searchStreamSigner) Send(resp *object.SearchResponse) error {
} }
func (s *SignService) Search(req *object.SearchRequest, stream SearchStream) error { func (s *SignService) Search(req *object.SearchRequest, stream SearchStream) error {
return s.sigSvc.HandleServerStreamRequest(req, return s.sigSvc.HandleServerStreamRequest(stream.Context(), req,
func(resp util.ResponseMessage) error { func(resp util.ResponseMessage) error {
return stream.Send(resp.(*object.SearchResponse)) return stream.Send(resp.(*object.SearchResponse))
}, },
@ -176,7 +176,7 @@ func (s *getRangeStreamSigner) Send(resp *object.GetRangeResponse) error {
} }
func (s *SignService) GetRange(req *object.GetRangeRequest, stream GetObjectRangeStream) error { func (s *SignService) GetRange(req *object.GetRangeRequest, stream GetObjectRangeStream) error {
return s.sigSvc.HandleServerStreamRequest(req, return s.sigSvc.HandleServerStreamRequest(stream.Context(), req,
func(resp util.ResponseMessage) error { func(resp util.ResponseMessage) error {
return stream.Send(resp.(*object.GetRangeResponse)) return stream.Send(resp.(*object.GetRangeResponse))
}, },

View file

@ -27,7 +27,7 @@ func (p *Replicator) HandleTask(ctx context.Context, task Task, res TaskResult)
if task.obj == nil { if task.obj == nil {
var err error var err error
task.obj, err = engine.Get(p.localStorage, task.addr) task.obj, err = engine.Get(ctx, p.localStorage, task.addr)
if err != nil { if err != nil {
p.log.Error("could not get object from local storage", p.log.Error("could not get object from local storage",
zap.Stringer("object", task.addr), zap.Stringer("object", task.addr),

View file

@ -8,6 +8,7 @@ import (
"sync" "sync"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
"github.com/hashicorp/golang-lru/v2/simplelru" "github.com/hashicorp/golang-lru/v2/simplelru"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -84,8 +85,15 @@ func dialTreeService(ctx context.Context, netmapAddr string) (*grpc.ClientConn,
return nil, err return nil, err
} }
opts := make([]grpc.DialOption, 1, 2) opts := []grpc.DialOption{
opts[0] = grpc.WithBlock() grpc.WithBlock(),
grpc.WithChainUnaryInterceptor(
tracing.NewGRPCUnaryClientInteceptor(),
),
grpc.WithChainStreamInterceptor(
tracing.NewGRPCStreamClientInterceptor(),
),
}
// FIXME(@fyrchik): ugly hack #1322 // FIXME(@fyrchik): ugly hack #1322
if !strings.HasPrefix(netAddr.URIAddr(), "grpcs:") { if !strings.HasPrefix(netAddr.URIAddr(), "grpcs:") {

View file

@ -10,6 +10,7 @@ import (
"math/rand" "math/rand"
"sync" "sync"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
@ -146,7 +147,14 @@ func (s *Service) synchronizeTree(ctx context.Context, cid cid.ID, from uint64,
return false return false
} }
cc, err := grpc.DialContext(egCtx, a.URIAddr(), grpc.WithTransportCredentials(insecure.NewCredentials())) cc, err := grpc.DialContext(egCtx, a.URIAddr(),
grpc.WithChainUnaryInterceptor(
tracing.NewGRPCUnaryClientInteceptor(),
),
grpc.WithChainStreamInterceptor(
tracing.NewGRPCStreamClientInterceptor(),
),
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil { if err != nil {
// Failed to connect, try the next address. // Failed to connect, try the next address.
return false return false

View file

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/pkg/tracing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -67,8 +68,7 @@ func (s *RequestMessageStreamer) Send(ctx context.Context, req any) error {
var err error var err error
// verify request signatures if err = verifyRequestSignature(ctx, req); err != nil {
if err = signature.VerifyServiceMessage(req); err != nil {
err = fmt.Errorf("could not verify request: %w", err) err = fmt.Errorf("could not verify request: %w", err)
} else { } else {
err = s.send(ctx, req) err = s.send(ctx, req)
@ -112,7 +112,7 @@ func (s *RequestMessageStreamer) CloseAndRecv(ctx context.Context) (ResponseMess
setStatusV2(resp, err) setStatusV2(resp, err)
} }
if err = signResponse(s.key, resp, s.statusSupported); err != nil { if err = signResponse(ctx, s.key, resp, s.statusSupported); err != nil {
return nil, err return nil, err
} }
@ -130,6 +130,7 @@ func (s *SignService) CreateRequestStreamer(sender RequestMessageWriter, closer
} }
func (s *SignService) HandleServerStreamRequest( func (s *SignService) HandleServerStreamRequest(
ctx context.Context,
req any, req any,
respWriter ResponseMessageWriter, respWriter ResponseMessageWriter,
blankResp ResponseConstructor, blankResp ResponseConstructor,
@ -142,12 +143,11 @@ func (s *SignService) HandleServerStreamRequest(
var err error var err error
// verify request signatures if err = verifyRequestSignature(ctx, req); err != nil {
if err = signature.VerifyServiceMessage(req); err != nil {
err = fmt.Errorf("could not verify request: %w", err) err = fmt.Errorf("could not verify request: %w", err)
} else { } else {
err = respWriterCaller(func(resp ResponseMessage) error { err = respWriterCaller(func(resp ResponseMessage) error {
if err := signResponse(s.key, resp, statusSupported); err != nil { if err := signResponse(ctx, s.key, resp, statusSupported); err != nil {
return err return err
} }
@ -164,7 +164,7 @@ func (s *SignService) HandleServerStreamRequest(
setStatusV2(resp, err) setStatusV2(resp, err)
_ = signResponse(s.key, resp, false) // panics or returns nil with false arg _ = signResponse(ctx, s.key, resp, false) // panics or returns nil with false arg
return respWriter(resp) return respWriter(resp)
} }
@ -183,8 +183,7 @@ func (s *SignService) HandleUnaryRequest(ctx context.Context, req any, handler U
err error err error
) )
// verify request signatures if err = verifyRequestSignature(ctx, req); err != nil {
if err = signature.VerifyServiceMessage(req); err != nil {
var sigErr apistatus.SignatureVerification var sigErr apistatus.SignatureVerification
sigErr.SetMessage(err.Error()) sigErr.SetMessage(err.Error())
@ -205,7 +204,7 @@ func (s *SignService) HandleUnaryRequest(ctx context.Context, req any, handler U
} }
// sign the response // sign the response
if err = signResponse(s.key, resp, statusSupported); err != nil { if err = signResponse(ctx, s.key, resp, statusSupported); err != nil {
return nil, err return nil, err
} }
@ -233,7 +232,10 @@ func setStatusV2(resp ResponseMessage, err error) {
// The signature error affects the result depending on the protocol version: // The signature error affects the result depending on the protocol version:
// - if status return is supported, panics since we cannot return the failed status, because it will not be signed; // - if status return is supported, panics since we cannot return the failed status, because it will not be signed;
// - otherwise, returns error in order to transport it directly. // - otherwise, returns error in order to transport it directly.
func signResponse(key *ecdsa.PrivateKey, resp any, statusSupported bool) error { func signResponse(ctx context.Context, key *ecdsa.PrivateKey, resp any, statusSupported bool) error {
_, span := tracing.StartSpanFromContext(ctx, "signResponse")
defer span.End()
err := signature.SignServiceMessage(key, resp) err := signature.SignServiceMessage(key, resp)
if err != nil { if err != nil {
err = fmt.Errorf("could not sign response: %w", err) err = fmt.Errorf("could not sign response: %w", err)
@ -247,3 +249,10 @@ func signResponse(key *ecdsa.PrivateKey, resp any, statusSupported bool) error {
return err return err
} }
func verifyRequestSignature(ctx context.Context, req any) error {
_, span := tracing.StartSpanFromContext(ctx, "verifyRequestSignature")
defer span.End()
return signature.VerifyServiceMessage(req)
}