diff --git a/cmd/neofs-lancet/internal/storage/get.go b/cmd/neofs-lancet/internal/storage/get.go index c3ee33f108..a879921abc 100644 --- a/cmd/neofs-lancet/internal/storage/get.go +++ b/cmd/neofs-lancet/internal/storage/get.go @@ -37,7 +37,7 @@ func getFunc(cmd *cobra.Command, _ []string) error { } defer storage.Close() - obj, err := storage.Get(addr) + obj, err := storage.Get(cmd.Context(), addr) if err != nil { return fmt.Errorf("could not fetch object: %w", err) } diff --git a/cmd/neofs-lancet/internal/storage/list.go b/cmd/neofs-lancet/internal/storage/list.go index ea3b925a64..78154fb174 100644 --- a/cmd/neofs-lancet/internal/storage/list.go +++ b/cmd/neofs-lancet/internal/storage/list.go @@ -38,7 +38,7 @@ func listFunc(cmd *cobra.Command, _ []string) error { cursor *engine.Cursor ) for { - addrs, cursor, err = storage.ListWithCursor(1024, cursor) + addrs, cursor, err = storage.ListWithCursor(cmd.Context(), 1024, cursor) if err != nil { if errors.Is(err, engine.ErrEndOfListing) { return nil diff --git a/cmd/neofs-lancet/internal/storage/status.go b/cmd/neofs-lancet/internal/storage/status.go index 7727854c1f..cfa586e6b1 100644 --- a/cmd/neofs-lancet/internal/storage/status.go +++ b/cmd/neofs-lancet/internal/storage/status.go @@ -34,7 +34,7 @@ func statusObject(cmd *cobra.Command, _ []string) error { return err } defer storage.Close() - status, err := storage.ObjectStatus(addr) + status, err := storage.ObjectStatus(cmd.Context(), addr) if err != nil { return fmt.Errorf("could not fetch object: %w", err) } diff --git a/cmd/neofs-node/container.go b/cmd/neofs-node/container.go index 9d459f1c48..1c0597bf3b 100644 --- a/cmd/neofs-node/container.go +++ b/cmd/neofs-node/container.go @@ -219,7 +219,7 @@ func reportHandler(c *cfg, logger *zap.Logger) timer.Tick { l.Debug("sending container reports to contract...") - idList, err := st.ListContainers() + idList, err := st.ListContainers(context.TODO()) if err != nil { l.Warn("engine's list containers failure", zap.Error(err)) return @@ -238,7 +238,7 @@ func reportHandler(c *cfg, logger *zap.Logger) timer.Tick { var successes int for _, cnr := range idList { - size, objsNum, err := st.ContainerInfo(cnr) + size, objsNum, err := st.ContainerInfo(context.TODO(), cnr) if err != nil { l.Warn("container's stat fetching error", zap.Stringer("cid", cnr), zap.Error(err)) return diff --git a/cmd/neofs-node/object.go b/cmd/neofs-node/object.go index 8e70c94131..00f3c35b2b 100644 --- a/cmd/neofs-node/object.go +++ b/cmd/neofs-node/object.go @@ -513,7 +513,7 @@ func (h *headerWriter) WriteHeader(o *object.Object) error { return nil } -func (h headerSource) Head(address oid.Address) (*object.Object, error) { +func (h headerSource) Head(ctx context.Context, address oid.Address) (*object.Object, error) { l := h.l.With(zap.Stringer("address", address)) l.Debug("requesting header") @@ -534,7 +534,7 @@ func (h headerSource) Head(address oid.Address) (*object.Object, error) { prm.WithAddress(address) prm.WithRawFlag(true) - err := h.getsvc.Head(context.Background(), prm) + err := h.getsvc.Head(ctx, prm) if err != nil { return nil, fmt.Errorf("reading header: %w", err) } @@ -656,12 +656,12 @@ type storageForObjectService struct { } // SearchObjects implements [objectService.Storage] interface. -func (x storageForObjectService) SearchObjects(cID cid.ID, fs []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]client.SearchResultItem, []byte, error) { - return x.local.Search(cID, fs, attrs, cursor, count) +func (x storageForObjectService) SearchObjects(ctx context.Context, cID cid.ID, fs []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]client.SearchResultItem, []byte, error) { + return x.local.Search(ctx, cID, fs, attrs, cursor, count) } -func (x storageForObjectService) VerifyAndStoreObjectLocally(obj object.Object) error { - return x.putSvc.ValidateAndStoreObjectLocally(obj) +func (x storageForObjectService) VerifyAndStoreObjectLocally(ctx context.Context, obj object.Object) error { + return x.putSvc.ValidateAndStoreObjectLocally(ctx, obj) } func (x storageForObjectService) GetSessionPrivateKey(account user.ID) (ecdsa.PrivateKey, error) { diff --git a/cmd/neofs-node/storage.go b/cmd/neofs-node/storage.go index 490db30558..fa11602a75 100644 --- a/cmd/neofs-node/storage.go +++ b/cmd/neofs-node/storage.go @@ -1,6 +1,7 @@ package main import ( + "context" "time" "github.com/nspcc-dev/bbolt" @@ -36,7 +37,7 @@ func initLocalStorage(c *cfg) { subscribeToContainerRemoval(c, func(id cid.ID, owner user.ID) { if owner.IsZero() { - err := ls.InhumeContainer(id) + err := ls.InhumeContainer(context.TODO(), id) if err != nil { c.log.Warn("inhuming container after a chain event", zap.Stringer("cID", id), zap.Error(err)) @@ -46,7 +47,7 @@ func initLocalStorage(c *cfg) { c.log.Info("caught container removal, marking its local objects for GC...", zap.Stringer("container", id), zap.Stringer("owner", owner)) - if err := ls.InhumeContainer(id); err != nil { + if err := ls.InhumeContainer(context.TODO(), id); err != nil { c.log.Warn("failed to mark local objects from the removed container for GC", zap.Stringer("container", id), zap.Error(err)) return diff --git a/pkg/core/object/ec_test.go b/pkg/core/object/ec_test.go index fd887ca08b..ec0de898d4 100644 --- a/pkg/core/object/ec_test.go +++ b/pkg/core/object/ec_test.go @@ -2,6 +2,7 @@ package objectcore import ( "bytes" + "context" "fmt" "testing" @@ -202,12 +203,12 @@ func TestFormatValidator_Validate_EC(t *testing.T) { obj.SetParent(&parent) tc.corruptPart(obj) }) - require.EqualError(t, v.Validate(&cp, false, true), tc.err) + require.EqualError(t, v.Validate(context.Background(), &cp, false, true), tc.err) return } cp := corruptPart(t, tc.corruptPart) - require.EqualError(t, v.Validate(&cp, false, true), tc.err) + require.EqualError(t, v.Validate(context.Background(), &cp, false, true), tc.err) }) } @@ -218,17 +219,17 @@ func TestFormatValidator_Validate_EC(t *testing.T) { obj.SetPayload(nil) obj.AssociateDeleted(oidtest.ID()) }) - require.EqualError(t, v.Validate(&cp, false, true), "mix of EC (__NEOFS__EC_RULE_IDX) and non-EC (__NEOFS__ASSOCIATE) attributes") + require.EqualError(t, v.Validate(context.Background(), &cp, false, true), "mix of EC (__NEOFS__EC_RULE_IDX) and non-EC (__NEOFS__ASSOCIATE) attributes") }) t.Run("blank", func(t *testing.T) { for i := range ecParts { - require.EqualError(t, v.Validate(&ecParts[i], true, true), "blank object with EC attributes") + require.EqualError(t, v.Validate(context.Background(), &ecParts[i], true, true), "blank object with EC attributes") } obj := blankValidObject(creator) obj.SetContainerID(cnrID) - require.NoError(t, v.Validate(obj, true, true)) + require.NoError(t, v.Validate(context.Background(), obj, true, true)) }) t.Run("non-EC container", func(t *testing.T) { @@ -241,7 +242,7 @@ func TestFormatValidator_Validate_EC(t *testing.T) { obj.SetContainerID(cnr) }) - require.EqualError(t, v.Validate(&cp, false, true), "object with EC attributes __NEOFS__EC_RULE_IDX in container without EC rules") + require.EqualError(t, v.Validate(context.Background(), &cp, false, true), "object with EC attributes __NEOFS__EC_RULE_IDX in container without EC rules") }) t.Run("split", func(t *testing.T) { @@ -312,7 +313,7 @@ func TestFormatValidator_Validate_EC(t *testing.T) { require.NoError(t, linker.SetVerificationFields(creator)) - require.NoError(t, v.Validate(&linker, false, true)) + require.NoError(t, v.Validate(context.Background(), &linker, false, true)) for i := range splitParts { parts, err := iec.Encode(irule, splitParts[i].Payload()) @@ -325,7 +326,7 @@ func TestFormatValidator_Validate_EC(t *testing.T) { }) require.NoError(t, err) - require.NoError(t, v.Validate(&ecPart, false, true)) + require.NoError(t, v.Validate(context.Background(), &ecPart, false, true)) } } }) @@ -339,11 +340,11 @@ func TestFormatValidator_Validate_EC(t *testing.T) { }) require.NoError(t, err) - require.NoError(t, v.Validate(&obj, false, true)) + require.NoError(t, v.Validate(context.Background(), &obj, false, true)) } }) for i := range ecParts { - require.NoError(t, v.Validate(&ecParts[i], false, true)) + require.NoError(t, v.Validate(context.Background(), &ecParts[i], false, true)) } } diff --git a/pkg/core/object/fmt.go b/pkg/core/object/fmt.go index 943351b448..db3b983c52 100644 --- a/pkg/core/object/fmt.go +++ b/pkg/core/object/fmt.go @@ -53,7 +53,7 @@ type DeleteHandler interface { // LockSource is a source of lock relations between the objects. type LockSource interface { // IsLocked must clarify object's lock status. - IsLocked(address oid.Address) (bool, error) + IsLocked(ctx context.Context, address oid.Address) (bool, error) } // Locker is an object lock storage interface. @@ -142,13 +142,13 @@ func NewFormatValidator(fsChain FSChain, netmapContract NetmapContract, containe // allowAllVersions defines whether the object version is checked. // // Returns nil error if the object has valid structure. -func (v *FormatValidator) Validate(obj *object.Object, unprepared, allowAllVersions bool) error { - return v.validate(obj, unprepared, allowAllVersions, 0) +func (v *FormatValidator) Validate(ctx context.Context, obj *object.Object, unprepared, allowAllVersions bool) error { + return v.validate(ctx, obj, unprepared, allowAllVersions, 0) } const maxObjectNestingLevel = 2 -func (v *FormatValidator) validate(obj *object.Object, unprepared, allowAllVersions bool, nestingLevel int) error { +func (v *FormatValidator) validate(ctx context.Context, obj *object.Object, unprepared, allowAllVersions bool, nestingLevel int) error { if obj == nil { return errNilObject } @@ -243,7 +243,7 @@ func (v *FormatValidator) validate(obj *object.Object, unprepared, allowAllVersi if err := v.checkAttributes(obj); err != nil { return fmt.Errorf("invalid attributes: %w", err) } - if err := v.checkExpiration(*obj, expirationRequired); err != nil { + if err := v.checkExpiration(ctx, *obj, expirationRequired); err != nil { return fmt.Errorf("expiration attribute: %w", err) } @@ -267,7 +267,7 @@ func (v *FormatValidator) validate(obj *object.Object, unprepared, allowAllVersi // it is possible to have a split of a split prepared := firstSet || splitID != nil || isEC - return v.validate(par, !prepared, allowAllVersions, nestingLevel+1) + return v.validate(ctx, par, !prepared, allowAllVersions, nestingLevel+1) } return nil @@ -293,7 +293,7 @@ func (i ContentMeta) Objects() []oid.ID { // ValidateContent validates payload content according to the object type. // Since it operates on a finalized object it also checks for some attributes // that can be omitted by [FormatValidator.Validate] for unprepared objects. -func (v *FormatValidator) ValidateContent(o *object.Object) error { +func (v *FormatValidator) ValidateContent(ctx context.Context, o *object.Object) error { switch o.Type() { case object.TypeRegular: // ignore regular objects, they do not need payload formatting @@ -319,7 +319,7 @@ func (v *FormatValidator) ValidateContent(o *object.Object) error { return fmt.Errorf("reading link object's payload: %w", err) } - err = v.sv.VerifySplit(context.Background(), cnr, firstObjID, testLink.Objects()) + err = v.sv.VerifySplit(ctx, cnr, firstObjID, testLink.Objects()) if err != nil { return fmt.Errorf("link object's split chain verification: %w", err) } @@ -333,7 +333,7 @@ func (v *FormatValidator) ValidateContent(o *object.Object) error { } if o.Type() == object.TypeTombstone { - return v.tv.VerifyTombStoneWithoutPayload(context.Background(), *o) + return v.tv.VerifyTombStoneWithoutPayload(ctx, *o) } default: // ignore all other object types, they do not need payload formatting @@ -343,7 +343,7 @@ func (v *FormatValidator) ValidateContent(o *object.Object) error { var errExpired = errors.New("object has expired") -func (v *FormatValidator) checkExpiration(obj object.Object, expirationRequired bool) error { +func (v *FormatValidator) checkExpiration(ctx context.Context, obj object.Object, expirationRequired bool) error { exp, err := Expiration(obj) if err != nil { if errors.Is(err, ErrNoExpiration) { @@ -367,7 +367,7 @@ func (v *FormatValidator) checkExpiration(obj object.Object, expirationRequired addr.SetContainer(cID) addr.SetObject(oID) - locked, err := v.e.IsLocked(addr) + locked, err := v.e.IsLocked(ctx, addr) if err != nil { return fmt.Errorf("locking status check for an expired object: %w", err) } diff --git a/pkg/core/object/fmt_test.go b/pkg/core/object/fmt_test.go index 21c1f5a795..b16eb655a5 100644 --- a/pkg/core/object/fmt_test.go +++ b/pkg/core/object/fmt_test.go @@ -56,7 +56,7 @@ type testLockSource struct { m map[oid.Address]bool } -func (t testLockSource) IsLocked(address oid.Address) (bool, error) { +func (t testLockSource) IsLocked(_ context.Context, address oid.Address) (bool, error) { return t.m[address], nil } @@ -95,7 +95,7 @@ func TestFormatValidator_Validate(t *testing.T) { require.NoError(t, err) t.Run("nil input", func(t *testing.T) { - require.Error(t, v.Validate(nil, true, true)) + require.Error(t, v.Validate(context.Background(), nil, true, true)) }) t.Run("storage group", func(t *testing.T) { @@ -103,19 +103,19 @@ func TestFormatValidator_Validate(t *testing.T) { obj.SetType(object.TypeStorageGroup) //nolint:staticcheck // Deprecated, but that's exactly the test. obj.SetContainerID(cidtest.ID()) - require.Error(t, v.Validate(obj, false, true)) - require.Error(t, v.Validate(obj, true, true)) + require.Error(t, v.Validate(context.Background(), obj, false, true)) + require.Error(t, v.Validate(context.Background(), obj, true, true)) }) t.Run("invalid identifier", func(t *testing.T) { t.Run("missing", func(t *testing.T) { obj := smallECDSASHA512 obj.ResetID() - require.ErrorIs(t, v.Validate(&obj, false, true), errNilID) + require.ErrorIs(t, v.Validate(context.Background(), &obj, false, true), errNilID) }) t.Run("wrong", func(t *testing.T) { registerContainer(wrongIDECDSASHA512.GetContainerID()) - require.EqualError(t, v.Validate(&wrongIDECDSASHA512, false, true), "could not validate header fields: invalid identifier: incorrect object identifier") + require.EqualError(t, v.Validate(context.Background(), &wrongIDECDSASHA512, false, true), "could not validate header fields: invalid identifier: incorrect object identifier") }) }) @@ -123,28 +123,28 @@ func TestFormatValidator_Validate(t *testing.T) { obj := new(object.Object) obj.SetID(oidtest.ID()) - require.ErrorIs(t, v.Validate(obj, true, true), errNilCID) + require.ErrorIs(t, v.Validate(context.Background(), obj, true, true), errNilCID) }) t.Run("invalid signature", func(t *testing.T) { t.Run("unsigned", func(t *testing.T) { obj, _ := minUnsignedObject(t) registerContainer(obj.GetContainerID()) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: missing signature") + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: missing signature") }) t.Run("too big verification script", func(t *testing.T) { obj, _ := minUnsignedObject(t) registerContainer(obj.GetContainerID()) sig := neofscrypto.NewSignatureFromRawKey(0, testutil.RandByteSlice(1025), testutil.RandByteSlice(1024)) obj.SetSignature(&sig) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: verification script len 1025 overflows limit 1024") + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: verification script len 1025 overflows limit 1024") }) t.Run("too big invocation script", func(t *testing.T) { obj, _ := minUnsignedObject(t) registerContainer(obj.GetContainerID()) sig := neofscrypto.NewSignatureFromRawKey(0, testutil.RandByteSlice(1024), testutil.RandByteSlice(1025)) obj.SetSignature(&sig) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: invocation script len 1025 overflows limit 1024") + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: invocation script len 1025 overflows limit 1024") }) t.Run("too big invocation script", func(t *testing.T) { obj := getUnsignedObject() @@ -162,7 +162,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: unsupported scheme 4") + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: unsupported scheme 4") }) t.Run("wrong scheme", func(t *testing.T) { obj, signer := minUnsignedObject(t) @@ -174,7 +174,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: scheme ECDSA_RFC6979_SHA256_WALLET_CONNECT: signature mismatch") + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: scheme ECDSA_RFC6979_SHA256_WALLET_CONNECT: signature mismatch") }) t.Run("invalid public key", func(t *testing.T) { obj, signer := minUnsignedObject(t) @@ -202,7 +202,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - require.EqualError(t, v.Validate(&obj, false, true), "authenticate: scheme ECDSA_SHA512: decode public key: "+tc.err) + require.EqualError(t, v.Validate(context.Background(), &obj, false, true), "authenticate: scheme ECDSA_SHA512: decode public key: "+tc.err) }) } }) @@ -224,7 +224,7 @@ func TestFormatValidator_Validate(t *testing.T) { cp[i]++ newSig := neofscrypto.NewSignatureFromRawKey(sig.Scheme(), sig.PublicKeyBytes(), cp) tc.object.SetSignature(&newSig) - require.EqualError(t, v.Validate(&tc.object, false, true), fmt.Sprintf("authenticate: scheme %s: signature mismatch", tc.scheme)) + require.EqualError(t, v.Validate(context.Background(), &tc.object, false, true), fmt.Sprintf("authenticate: scheme %s: signature mismatch", tc.scheme)) } }) } @@ -244,7 +244,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - require.NoError(t, v.Validate(obj, false, true)) + require.NoError(t, v.Validate(context.Background(), obj, false, true)) }) t.Run("incorrect session token", func(t *testing.T) { @@ -258,14 +258,14 @@ func TestFormatValidator_Validate(t *testing.T) { require.NoError(t, obj.SetIDWithSignature(signer)) obj.SetSignature(&neofscrypto.Signature{}) - require.Error(t, v.Validate(obj, false, true)) + require.Error(t, v.Validate(context.Background(), obj, false, true)) }) t.Run("wrong owner", func(t *testing.T) { obj.SetOwner(user.ID{}) require.NoError(t, obj.SetIDWithSignature(signer)) - require.Error(t, v.Validate(obj, false, true)) + require.Error(t, v.Validate(context.Background(), obj, false, true)) }) t.Run("wrong signer", func(t *testing.T) { @@ -275,7 +275,7 @@ func TestFormatValidator_Validate(t *testing.T) { wrongSigner := user.NewAutoIDSignerRFC6979(wrongOwner.PrivateKey) require.NoError(t, obj.SetIDWithSignature(wrongSigner)) - require.Error(t, v.Validate(obj, false, true)) + require.Error(t, v.Validate(context.Background(), obj, false, true)) }) t.Run("signed not by issuer", func(t *testing.T) { @@ -297,7 +297,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - err = v.Validate(obj, false, true) + err = v.Validate(context.Background(), obj, false, true) require.EqualError(t, err, "authenticate: session token: issuer mismatches signature") }) }) @@ -310,7 +310,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(obj.GetContainerID()) - require.NoError(t, v.Validate(obj, false, true)) + require.NoError(t, v.Validate(context.Background(), obj, false, true)) }) t.Run("expiration", func(t *testing.T) { @@ -333,7 +333,7 @@ func TestFormatValidator_Validate(t *testing.T) { t.Run("invalid attribute value", func(t *testing.T) { val := "text" - err := v.Validate(fn(val), false, true) + err := v.Validate(context.Background(), fn(val), false, true) require.Error(t, err) }) @@ -342,7 +342,7 @@ func TestFormatValidator_Validate(t *testing.T) { obj := fn(val) t.Run("non-locked", func(t *testing.T) { - err := v.Validate(obj, false, true) + err := v.Validate(context.Background(), obj, false, true) require.ErrorIs(t, err, errExpired) }) @@ -355,14 +355,14 @@ func TestFormatValidator_Validate(t *testing.T) { addr.SetObject(oID) ls.m[addr] = true - err := v.Validate(obj, false, true) + err := v.Validate(context.Background(), obj, false, true) require.NoError(t, err) }) }) t.Run("alive object", func(t *testing.T) { val := strconv.FormatUint(curEpoch, 10) - err := v.Validate(fn(val), true, true) + err := v.Validate(context.Background(), fn(val), true, true) require.NoError(t, err) }) }) @@ -417,15 +417,15 @@ func TestFormatValidator_Validate(t *testing.T) { } t.Run("in key", func(t *testing.T) { obj := objWithAttr("k\x00y", "value") - require.EqualError(t, v.Validate(obj, true, true), "invalid attributes: invalid attribute #1: invalid key: illegal zero byte") + require.EqualError(t, v.Validate(context.Background(), obj, true, true), "invalid attributes: invalid attribute #1: invalid key: illegal zero byte") obj.SetID(oidtest.ID()) - require.EqualError(t, v.Validate(obj, false, true), "invalid attributes: invalid attribute #1: invalid key: illegal zero byte") + require.EqualError(t, v.Validate(context.Background(), obj, false, true), "invalid attributes: invalid attribute #1: invalid key: illegal zero byte") }) t.Run("in value", func(t *testing.T) { obj := objWithAttr("key", "va\x00ue") - require.EqualError(t, v.Validate(obj, true, true), "invalid attributes: invalid attribute #1: invalid value: illegal zero byte") + require.EqualError(t, v.Validate(context.Background(), obj, true, true), "invalid attributes: invalid attribute #1: invalid value: illegal zero byte") obj.SetID(oidtest.ID()) - require.EqualError(t, v.Validate(obj, false, true), "invalid attributes: invalid attribute #1: invalid value: illegal zero byte") + require.EqualError(t, v.Validate(context.Background(), obj, false, true), "invalid attributes: invalid attribute #1: invalid value: illegal zero byte") }) }) }) @@ -437,7 +437,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(child.GetContainerID()) - require.EqualError(t, v.Validate(&child, true, true), "max object nesting level 2 overflow") + require.EqualError(t, v.Validate(context.Background(), &child, true, true), "max object nesting level 2 overflow") }) t.Run("nesting is ok", func(t *testing.T) { @@ -446,7 +446,7 @@ func TestFormatValidator_Validate(t *testing.T) { registerContainer(child.GetContainerID()) - require.NoError(t, v.Validate(&child, true, true)) + require.NoError(t, v.Validate(context.Background(), &child, true, true)) }) }) @@ -459,7 +459,7 @@ func TestFormatValidator_Validate(t *testing.T) { {scheme: neofscrypto.ECDSA_WALLETCONNECT, object: smallECDSAWalletConnect}, } { t.Run(tc.scheme.String(), func(t *testing.T) { - require.NoError(t, v.Validate(&tc.object, false, true)) + require.NoError(t, v.Validate(context.Background(), &tc.object, false, true)) }) } } @@ -531,7 +531,7 @@ func TestLinkObjectSplitV2(t *testing.T) { obj.SetFirstID(oidtest.ID()) t.Run("V1 split, first is set", func(t *testing.T) { - require.ErrorContains(t, v.Validate(obj, true, true), "first object ID is set") + require.ErrorContains(t, v.Validate(context.Background(), obj, true, true), "first object ID is set") }) t.Run("V2 split", func(t *testing.T) { @@ -541,7 +541,7 @@ func TestLinkObjectSplitV2(t *testing.T) { obj.SetFirstID(oidtest.ID()) obj.SetType(object.TypeLink) - require.ErrorContains(t, v.Validate(obj, true, true), "incorrect link object's parent header") + require.ErrorContains(t, v.Validate(context.Background(), obj, true, true), "incorrect link object's parent header") }) t.Run("middle child does not have previous object ID", func(t *testing.T) { @@ -550,7 +550,7 @@ func TestLinkObjectSplitV2(t *testing.T) { obj.SetFirstID(oidtest.ID()) obj.SetType(object.TypeRegular) - require.ErrorContains(t, v.Validate(obj, true, true), "middle part does not have previous object ID") + require.ErrorContains(t, v.Validate(context.Background(), obj, true, true), "middle part does not have previous object ID") }) }) } @@ -575,7 +575,7 @@ func TestVersion(t *testing.T) { vers := version.New(2, 17) obj.SetVersion(&vers) - require.NoError(t, v.Validate(&obj, true, true)) + require.NoError(t, v.Validate(context.Background(), &obj, true, true)) }) t.Run("PUT", func(t *testing.T) { @@ -583,19 +583,19 @@ func TestVersion(t *testing.T) { vers := version.New(2, 17) obj.SetVersion(&vers) - require.Error(t, v.Validate(&obj, true, false), "invalid version for a non-replicated object") + require.Error(t, v.Validate(context.Background(), &obj, true, false), "invalid version for a non-replicated object") }) t.Run("2.18+", func(t *testing.T) { vers := version.New(2, 18) obj.SetVersion(&vers) - require.NoError(t, v.Validate(&obj, true, true)) + require.NoError(t, v.Validate(context.Background(), &obj, true, true)) vers = version.New(2, 100) obj.SetVersion(&vers) - require.NoError(t, v.Validate(&obj, true, true)) + require.NoError(t, v.Validate(context.Background(), &obj, true, true)) }) }) } diff --git a/pkg/local_object_storage/engine/bench_test.go b/pkg/local_object_storage/engine/bench_test.go index 9e45ef7f46..bfad71c263 100644 --- a/pkg/local_object_storage/engine/bench_test.go +++ b/pkg/local_object_storage/engine/bench_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "fmt" "os" @@ -133,7 +134,7 @@ func benchmarkSearch(b *testing.B, fx *benchmarkEngineFixture, container cid.ID, b.ReportAllocs() for b.Loop() { dropCachesIfEnabled(b) - _, nextCursor, err := fx.engine.Search(container, fs, attrs, cursor, 1000) + _, nextCursor, err := fx.engine.Search(context.Background(), container, fs, attrs, cursor, 1000) if err != nil { b.Fatal(err) } @@ -150,7 +151,7 @@ func benchmarkListWithCursor(b *testing.B, fx *benchmarkEngineFixture, batchSize var cursor *Cursor var err error for { - _, cursor, err = fx.engine.ListWithCursor(batchSize, cursor) + _, cursor, err = fx.engine.ListWithCursor(context.Background(), batchSize, cursor) if errors.Is(err, ErrEndOfListing) { break } diff --git a/pkg/local_object_storage/engine/container.go b/pkg/local_object_storage/engine/container.go index 1a18b475c1..72747e3556 100644 --- a/pkg/local_object_storage/engine/container.go +++ b/pkg/local_object_storage/engine/container.go @@ -16,7 +16,7 @@ import ( // objects. // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) ContainerInfo(cnr cid.ID) (uint64, uint64, error) { +func (e *StorageEngine) ContainerInfo(_ context.Context, cnr cid.ID) (uint64, uint64, error) { if e.metrics != nil { defer elapsed(e.metrics.AddEstimateContainerSizeDuration)() } @@ -49,7 +49,7 @@ func (e *StorageEngine) ContainerInfo(cnr cid.ID) (uint64, uint64, error) { // ListContainers returns a unique container IDs presented in the engine objects. // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) ListContainers() ([]cid.ID, error) { +func (e *StorageEngine) ListContainers(_ context.Context) ([]cid.ID, error) { if e.metrics != nil { defer elapsed(e.metrics.AddListContainersDuration)() } diff --git a/pkg/local_object_storage/engine/container_test.go b/pkg/local_object_storage/engine/container_test.go index 05a176e98e..e8aa0850ed 100644 --- a/pkg/local_object_storage/engine/container_test.go +++ b/pkg/local_object_storage/engine/container_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "path/filepath" "strconv" @@ -47,17 +48,17 @@ func TestStorageEngine_ContainerCleanUp(t *testing.T) { o2 := generateObjectWithCID(cidtest.ID()) o2.SetPayload(make([]byte, errSmallSize+1)) - err := e.Put(o1, nil) + err := e.Put(context.Background(), o1, nil) require.NoError(t, err) - err = e.Put(o2, nil) + err = e.Put(context.Background(), o2, nil) require.NoError(t, err) require.NoError(t, e.Init()) time.Sleep(time.Second) - _, err1 := e.Get(o1.Address()) - _, err2 := e.Get(o2.Address()) + _, err1 := e.Get(context.Background(), o1.Address()) + _, err2 := e.Get(context.Background(), o2.Address()) require.ErrorIs(t, err1, new(apistatus.ObjectNotFound)) require.ErrorIs(t, err2, new(apistatus.ObjectNotFound)) diff --git a/pkg/local_object_storage/engine/control_test.go b/pkg/local_object_storage/engine/control_test.go index 0aeb3f6367..90f984ea82 100644 --- a/pkg/local_object_storage/engine/control_test.go +++ b/pkg/local_object_storage/engine/control_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "fmt" "os" @@ -124,7 +125,7 @@ func TestExecBlocks(t *testing.T) { addr := obj.Address() - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) // block executions errBlock := errors.New("block exec err") @@ -132,20 +133,20 @@ func TestExecBlocks(t *testing.T) { require.NoError(t, e.BlockExecution(errBlock)) // try to exec some op - _, err := e.Head(addr, false) + _, err := e.Head(context.Background(), addr, false) require.ErrorIs(t, err, errBlock) // resume executions require.NoError(t, e.ResumeExecution()) - _, err = e.Head(addr, false) // can be any data-related op + _, err = e.Head(context.Background(), addr, false) // can be any data-related op require.NoError(t, err) // close require.NoError(t, e.Close()) // try exec after close - _, err = e.Head(addr, false) + _, err = e.Head(context.Background(), addr, false) require.Error(t, err) // try to resume diff --git a/pkg/local_object_storage/engine/delete.go b/pkg/local_object_storage/engine/delete.go index a8e2a8e529..8c8e129819 100644 --- a/pkg/local_object_storage/engine/delete.go +++ b/pkg/local_object_storage/engine/delete.go @@ -1,6 +1,7 @@ package engine import ( + "context" "slices" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard" @@ -15,7 +16,7 @@ import ( // just marks the address for later removal by GC according to GC settings. // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) Delete(addr oid.Address) error { +func (e *StorageEngine) Delete(_ context.Context, addr oid.Address) error { if e.metrics != nil { defer elapsed(e.metrics.AddDeleteDuration)() } @@ -36,7 +37,7 @@ func (e *StorageEngine) Delete(addr oid.Address) error { // // Returns an error if executions are blocked (see BlockExecution) or if none of // the provided shards is found in the engine. -func (e *StorageEngine) DeleteRedundantCopies(addr oid.Address, shardIDs []string) error { +func (e *StorageEngine) DeleteRedundantCopies(_ context.Context, addr oid.Address, shardIDs []string) error { if e.metrics != nil { defer elapsed(e.metrics.AddDeleteDuration)() } @@ -92,7 +93,7 @@ func (e *StorageEngine) DeleteRedundantCopies(addr oid.Address, shardIDs []strin // (like [StorageEngine.Delete] does). // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) Drop(addr oid.Address) error { +func (e *StorageEngine) Drop(_ context.Context, addr oid.Address) error { if e.metrics != nil { defer elapsed(e.metrics.AddDropDuration)() } diff --git a/pkg/local_object_storage/engine/delete_test.go b/pkg/local_object_storage/engine/delete_test.go index ed5298eb8e..5d43ec8488 100644 --- a/pkg/local_object_storage/engine/delete_test.go +++ b/pkg/local_object_storage/engine/delete_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "testing" apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" @@ -14,8 +15,12 @@ import ( func TestDeleteBigObject(t *testing.T) { funcs := map[string]func(*StorageEngine, oid.Address) error{ - "delete": (*StorageEngine).Delete, - "drop": (*StorageEngine).Drop, + "delete": func(e *StorageEngine, addr oid.Address) error { + return e.Delete(context.Background(), addr) + }, + "drop": func(e *StorageEngine, addr oid.Address) error { + return e.Drop(context.Background(), addr) + }, } for name, fun := range funcs { t.Run(name, func(t *testing.T) { testDeleteBigObject(t, fun) }) @@ -62,9 +67,9 @@ func testDeleteBigObject(t *testing.T, fun func(*StorageEngine, oid.Address) err defer e.Close() for i := range children { - require.NoError(t, e.Put(children[i], nil)) + require.NoError(t, e.Put(context.Background(), children[i], nil)) } - require.NoError(t, e.Put(link, nil)) + require.NoError(t, e.Put(context.Background(), link, nil)) var splitErr *object.SplitInfoError @@ -89,7 +94,7 @@ func testDeleteBigObject(t *testing.T, fun func(*StorageEngine, oid.Address) err } func checkGetError(t *testing.T, e *StorageEngine, addr oid.Address, expected any) { - _, err := e.Get(addr) + _, err := e.Get(context.Background(), addr) if expected != nil { require.ErrorAs(t, err, expected) } else { diff --git a/pkg/local_object_storage/engine/ec.go b/pkg/local_object_storage/engine/ec.go index 042df7c40b..e9bdf2807b 100644 --- a/pkg/local_object_storage/engine/ec.go +++ b/pkg/local_object_storage/engine/ec.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "io" "time" @@ -17,7 +18,7 @@ import ( // ReadECPart is a buffered alternative for [StorageEngine.GetECPart] similar to // [StorageEngine.ReadObject]. -func (e *StorageEngine) ReadECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, io.ReadCloser, error) { +func (e *StorageEngine) ReadECPart(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddReadECPartDuration)() } @@ -55,7 +56,7 @@ func (e *StorageEngine) ReadECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo, b // // If object is locked (e.g. via [StorageEngine.Lock] or stored locker object), // GetECPart ignores expiration, tombstone and garbage marks. -func (e *StorageEngine) GetECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) { +func (e *StorageEngine) GetECPart(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddGetECPartDuration)() } @@ -145,7 +146,7 @@ loop: // ReadECPartRange is a buffered alternative for [StorageEngine.GetECPartRange] // similar to [StorageEngine.ReadECPart]. -func (e *StorageEngine) ReadECPartRange(cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64, buf []byte) (io.ReadCloser, error) { +func (e *StorageEngine) ReadECPartRange(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64, buf []byte) (io.ReadCloser, error) { var stream io.ReadCloser err := e.getECPartRangeFunc(cnr, parent, pi, off, ln, MetricRegister.AddReadECPartRangeDuration, func(s shardInterface, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) error { @@ -186,7 +187,7 @@ func (e *StorageEngine) ReadECPartRange(cnr cid.ID, parent oid.ID, pi iec.PartIn // [apistatus.ErrObjectOutOfRange]. // // Range bounds are limited by int64. -func (e *StorageEngine) GetECPartRange(cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) (uint64, io.ReadCloser, error) { +func (e *StorageEngine) GetECPartRange(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) (uint64, io.ReadCloser, error) { var pldLen uint64 var stream io.ReadCloser @@ -276,7 +277,7 @@ loop: // ReadECPartHeader is a buffered alternative for [StorageEngine.HeadECPart] // similar to [StorageEngine.ReadHeader]. -func (e *StorageEngine) ReadECPartHeader(cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, error) { +func (e *StorageEngine) ReadECPartHeader(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, error) { if e.metrics != nil { defer elapsed(e.metrics.AddReadECPartHeaderDuration)() } @@ -294,7 +295,7 @@ func (e *StorageEngine) ReadECPartHeader(cnr cid.ID, parent oid.ID, pi iec.PartI } // HeadECPart is similar to [StorageEngine.GetECPart] but returns only the header. -func (e *StorageEngine) HeadECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, error) { +func (e *StorageEngine) HeadECPart(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, error) { if e.metrics != nil { defer elapsed(e.metrics.AddHeadECPartDuration)() } diff --git a/pkg/local_object_storage/engine/ec_test.go b/pkg/local_object_storage/engine/ec_test.go index 22e575cfb6..4bd4254763 100644 --- a/pkg/local_object_storage/engine/ec_test.go +++ b/pkg/local_object_storage/engine/ec_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "encoding/json" "errors" "fmt" @@ -51,10 +52,10 @@ func TestStorageEngine_GetECPart(t *testing.T) { e := errors.New("any error") require.NoError(t, s.BlockExecution(e)) - _, _, err := s.GetECPart(cnr, parentID, pi) + _, _, err := s.GetECPart(context.Background(), cnr, parentID, pi) require.Equal(t, e, err) - _, _, err = s.ReadECPart(cnr, parentID, pi, make([]byte, 40<<10)) + _, _, err = s.ReadECPart(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.Equal(t, e, err) }) @@ -83,10 +84,10 @@ func TestStorageEngine_GetECPart(t *testing.T) { s := newEngineWithFixedShardOrder([]shardInterface{shardOK, unimplementedShard{}}) // to ensure 2nd shard is not accessed s.metrics = &m - _, _, _ = s.GetECPart(cnr, parentID, pi) + _, _, _ = s.GetECPart(context.Background(), cnr, parentID, pi) require.GreaterOrEqual(t, time.Duration(m.getECPart.Load()), sleepTime) - _, _, _ = s.ReadECPart(cnr, parentID, pi, make([]byte, 40<<10)) + _, _, _ = s.ReadECPart(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.GreaterOrEqual(t, time.Duration(m.readECPart.Load()), sleepTime) }) @@ -101,13 +102,13 @@ func TestStorageEngine_GetECPart(t *testing.T) { s.log = l require.PanicsWithValue(t, "zero object ID returned as error", func() { - _, _, _ = s.GetECPart(cnr, parentID, pi) + _, _, _ = s.GetECPart(context.Background(), cnr, parentID, pi) }) lb.AssertEmpty() require.PanicsWithValue(t, "zero object ID returned as error", func() { - _, _, _ = s.ReadECPart(cnr, parentID, pi, make([]byte, 40<<10)) + _, _, _ = s.ReadECPart(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) }) lb.AssertEmpty() @@ -139,13 +140,13 @@ func TestStorageEngine_GetECPart(t *testing.T) { } checkOK := func(t *testing.T, s *StorageEngine) { - hdr, rdr, err := s.GetECPart(cnr, parentID, pi) + hdr, rdr, err := s.GetECPart(context.Background(), cnr, parentID, pi) require.NoError(t, err) assertGetECPartOK(t, partObj, hdr, rdr) } checkOKBuffered := func(t *testing.T, s *StorageEngine) { buf := make([]byte, 40<<10) - n, rdr, err := s.ReadECPart(cnr, parentID, pi, buf) + n, rdr, err := s.ReadECPart(context.Background(), cnr, parentID, pi, buf) require.NoError(t, err) require.Equal(t, partObj.CutPayload().Marshal(), buf[:n]) tail, err := io.ReadAll(rdr) @@ -154,11 +155,11 @@ func TestStorageEngine_GetECPart(t *testing.T) { require.NoError(t, rdr.Close()) } checkErrorIs := func(t *testing.T, s *StorageEngine, e error) { - _, _, err := s.GetECPart(cnr, parentID, pi) + _, _, err := s.GetECPart(context.Background(), cnr, parentID, pi) require.ErrorIs(t, err, e) } checkErrorIsBuffered := func(t *testing.T, s *StorageEngine, e error) { - _, _, err := s.ReadECPart(cnr, parentID, pi, make([]byte, 40<<10)) + _, _, err := s.ReadECPart(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.ErrorIs(t, err, e) } @@ -472,9 +473,9 @@ func TestStorageEngine_GetECPart(t *testing.T) { sysObj.SetPayload([]byte{}) addAttribute(&sysObj, "__NEOFS__EXPIRATION_EPOCH", strconv.Itoa(123)) - require.NoError(t, s.Put(&sysObj, nil)) + require.NoError(t, s.Put(context.Background(), &sysObj, nil)) - hdr, rdr, err := s.GetECPart(cnr, sysObj.GetID(), pi) + hdr, rdr, err := s.GetECPart(context.Background(), cnr, sysObj.GetID(), pi) require.NoError(t, err) assertGetECPartOK(t, sysObj, hdr, rdr) }) @@ -491,13 +492,13 @@ func TestStorageEngine_GetECPart(t *testing.T) { linker.SetParentID(parentID) linker.SetPayload(payload) - require.NoError(t, s.Put(&linker, nil)) + require.NoError(t, s.Put(context.Background(), &linker, nil)) - hdr, rdr, err := s.GetECPart(cnr, parentID, pi) + hdr, rdr, err := s.GetECPart(context.Background(), cnr, parentID, pi) require.NoError(t, err) assertGetECPartOK(t, linker, hdr, rdr) - hdr, rdr, err = s.GetECPart(cnr, linker.GetID(), pi) + hdr, rdr, err = s.GetECPart(context.Background(), cnr, linker.GetID(), pi) require.NoError(t, err) assertGetECPartOK(t, linker, hdr, rdr) }) @@ -530,7 +531,7 @@ func TestStorageEngine_GetECPartRange(t *testing.T) { e := errors.New("any error") require.NoError(t, s.BlockExecution(e)) - _, _, err := s.GetECPartRange(cnr, parentID, pi, 0, 1) + _, _, err := s.GetECPartRange(context.Background(), cnr, parentID, pi, 0, 1) require.Equal(t, e, err) }) @@ -563,7 +564,7 @@ func TestStorageEngine_GetECPartRange(t *testing.T) { s := newEngineWithFixedShardOrder([]shardInterface{shardOK, unimplementedShard{}}) // to ensure 2nd shard is not accessed s.metrics = &m - _, _, _ = s.GetECPartRange(cnr, parentID, pi, off, ln) + _, _, _ = s.GetECPartRange(context.Background(), cnr, parentID, pi, off, ln) require.GreaterOrEqual(t, time.Duration(m.getECPartRange.Load()), sleepTime) }) @@ -578,7 +579,7 @@ func TestStorageEngine_GetECPartRange(t *testing.T) { s.log = l require.PanicsWithValue(t, "zero object ID returned as error", func() { - _, _, _ = s.GetECPartRange(cnr, parentID, pi, off, ln) + _, _, _ = s.GetECPartRange(context.Background(), cnr, parentID, pi, off, ln) }) lb.AssertEmpty() @@ -615,12 +616,12 @@ func TestStorageEngine_GetECPartRange(t *testing.T) { } checkOK := func(t *testing.T, s *StorageEngine) { - pldLen, rc, err := s.GetECPartRange(cnr, parentID, pi, off, ln) + pldLen, rc, err := s.GetECPartRange(context.Background(), cnr, parentID, pi, off, ln) require.NoError(t, err) assertGetECPartRangeOK(t, partObj, off, ln, pldLen, rc) } checkErrorIs := func(t *testing.T, s *StorageEngine, e error) { - _, _, err := s.GetECPartRange(cnr, parentID, pi, off, ln) + _, _, err := s.GetECPartRange(context.Background(), cnr, parentID, pi, off, ln) require.ErrorIs(t, err, e) } @@ -921,13 +922,13 @@ func TestStorageEngine_GetECPartRange(t *testing.T) { sysObj.SetPayload([]byte{}) addAttribute(&sysObj, "__NEOFS__EXPIRATION_EPOCH", strconv.Itoa(123)) - require.NoError(t, s.Put(&sysObj, nil)) + require.NoError(t, s.Put(context.Background(), &sysObj, nil)) - gotLen, rc, err := s.GetECPartRange(cnr, sysObj.GetID(), pi, 0, 0) + gotLen, rc, err := s.GetECPartRange(context.Background(), cnr, sysObj.GetID(), pi, 0, 0) require.NoError(t, err) assertGetECPartRangeOK(t, sysObj, 0, 0, gotLen, rc) - _, _, err = s.GetECPartRange(cnr, sysObj.GetID(), pi, 0, 1) + _, _, err = s.GetECPartRange(context.Background(), cnr, sysObj.GetID(), pi, 0, 1) require.ErrorIs(t, err, apistatus.ErrObjectOutOfRange) }) } @@ -956,10 +957,10 @@ func TestStorageEngine_HeadECPart(t *testing.T) { e := errors.New("any error") require.NoError(t, s.BlockExecution(e)) - _, err := s.HeadECPart(cnr, parentID, pi) + _, err := s.HeadECPart(context.Background(), cnr, parentID, pi) require.Equal(t, e, err) - _, err = s.ReadECPartHeader(cnr, parentID, pi, nil) + _, err = s.ReadECPartHeader(context.Background(), cnr, parentID, pi, nil) require.Equal(t, e, err) }) @@ -990,10 +991,10 @@ func TestStorageEngine_HeadECPart(t *testing.T) { s := newEngineWithFixedShardOrder([]shardInterface{shardOK, unimplementedShard{}}) // to ensure 2nd shard is not accessed s.metrics = &m - _, _ = s.HeadECPart(cnr, parentID, pi) + _, _ = s.HeadECPart(context.Background(), cnr, parentID, pi) require.GreaterOrEqual(t, time.Duration(m.headECPart.Load()), sleepTime) - _, _ = s.ReadECPartHeader(cnr, parentID, pi, make([]byte, 40<<10)) + _, _ = s.ReadECPartHeader(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.GreaterOrEqual(t, time.Duration(m.readECPartHeader.Load()), sleepTime) }) @@ -1008,13 +1009,13 @@ func TestStorageEngine_HeadECPart(t *testing.T) { s.log = l require.PanicsWithValue(t, "zero object ID returned as error", func() { - _, _ = s.HeadECPart(cnr, parentID, pi) + _, _ = s.HeadECPart(context.Background(), cnr, parentID, pi) }) lb.AssertEmpty() require.PanicsWithValue(t, "zero object ID returned as error", func() { - _, _ = s.ReadECPartHeader(cnr, parentID, pi, nil) + _, _ = s.ReadECPartHeader(context.Background(), cnr, parentID, pi, nil) }) lb.AssertEmpty() @@ -1046,22 +1047,22 @@ func TestStorageEngine_HeadECPart(t *testing.T) { } checkOK := func(t *testing.T, s *StorageEngine) { - hdr, err := s.HeadECPart(cnr, parentID, pi) + hdr, err := s.HeadECPart(context.Background(), cnr, parentID, pi) require.NoError(t, err) require.Equal(t, partHdr, hdr) } checkOKBuffered := func(t *testing.T, s *StorageEngine) { buf := make([]byte, 40<<10) - n, err := s.ReadECPartHeader(cnr, parentID, pi, buf) + n, err := s.ReadECPartHeader(context.Background(), cnr, parentID, pi, buf) require.NoError(t, err) require.Equal(t, partHdr.Marshal(), buf[:n]) } checkErrorIs := func(t *testing.T, s *StorageEngine, e error) { - _, err = s.ReadECPartHeader(cnr, parentID, pi, make([]byte, 40<<10)) + _, err = s.ReadECPartHeader(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.ErrorIs(t, err, e) } checkErrorIsBuffered := func(t *testing.T, s *StorageEngine, e error) { - _, err = s.ReadECPartHeader(cnr, parentID, pi, make([]byte, 40<<10)) + _, err = s.ReadECPartHeader(context.Background(), cnr, parentID, pi, make([]byte, 40<<10)) require.ErrorIs(t, err, e) } @@ -1374,14 +1375,14 @@ func TestStorageEngine_HeadECPart(t *testing.T) { tc.associate(&sysObj, oidtest.ID()) addAttribute(&sysObj, "__NEOFS__EXPIRATION_EPOCH", strconv.Itoa(123)) - require.NoError(t, s.Put(&sysObj, nil)) + require.NoError(t, s.Put(context.Background(), &sysObj, nil)) - hdr, err := s.HeadECPart(cnr, sysObj.GetID(), pi) + hdr, err := s.HeadECPart(context.Background(), cnr, sysObj.GetID(), pi) require.NoError(t, err) require.Equal(t, sysObj, hdr) buf := make([]byte, 40<<10) - n, err := s.ReadECPartHeader(cnr, sysObj.GetID(), pi, buf) + n, err := s.ReadECPartHeader(context.Background(), cnr, sysObj.GetID(), pi, buf) require.NoError(t, err) require.Equal(t, sysObj.Marshal(), buf[:n]) }) @@ -1464,7 +1465,7 @@ func testPutTombstoneEC(t *testing.T) { assertSearch := func(t *testing.T, addrs []oid.Address) { fs, crs, err := objectcore.PreprocessSearchQuery(nil, nil, "") require.NoError(t, err) - res, newCrs, err := s.Search(cnr, fs, nil, crs, 1000) + res, newCrs, err := s.Search(context.Background(), cnr, fs, nil, crs, 1000) require.NoError(t, err) require.Zero(t, newCrs) require.Len(t, res, len(addrs)) @@ -1474,33 +1475,33 @@ func testPutTombstoneEC(t *testing.T) { } assertGetErrors := func(t *testing.T, target error) { - _, err := s.Get(parentAddr) + _, err := s.Get(context.Background(), parentAddr) require.ErrorIs(t, err, target) - _, _, err = s.GetStream(parentAddr) + _, _, err = s.GetStream(context.Background(), parentAddr) require.ErrorIs(t, err, target) - _, err = s.GetBytes(parentAddr) + _, err = s.GetBytes(context.Background(), parentAddr) require.ErrorIs(t, err, target) - _, err = s.GetRange(parentAddr, 0, 1) + _, err = s.GetRange(context.Background(), parentAddr, 0, 1) require.ErrorIs(t, err, target) - _, err = s.Head(parentAddr, false) + _, err = s.Head(context.Background(), parentAddr, false) require.ErrorIs(t, err, target) - _, err = s.Head(parentAddr, true) + _, err = s.Head(context.Background(), parentAddr, true) require.ErrorIs(t, err, target) for i := range parts { - _, err := s.Get(partAddrs[i]) + _, err := s.Get(context.Background(), partAddrs[i]) require.ErrorIs(t, err, target) - _, _, err = s.GetStream(partAddrs[i]) + _, _, err = s.GetStream(context.Background(), partAddrs[i]) require.ErrorIs(t, err, target) - _, err = s.GetBytes(partAddrs[i]) + _, err = s.GetBytes(context.Background(), partAddrs[i]) require.ErrorIs(t, err, target) - _, err = s.GetRange(partAddrs[i], 0, 1) + _, err = s.GetRange(context.Background(), partAddrs[i], 0, 1) require.ErrorIs(t, err, target) - _, err = s.Head(partAddrs[i], false) + _, err = s.Head(context.Background(), partAddrs[i], false) require.ErrorIs(t, err, target) - _, err = s.Head(partAddrs[i], true) + _, err = s.Head(context.Background(), partAddrs[i], true) require.ErrorIs(t, err, target) - _, _, err = s.GetECPart(cnr, parent.GetID(), iec.PartInfo{RuleIndex: ruleIdx, Index: i}) + _, _, err = s.GetECPart(context.Background(), cnr, parent.GetID(), iec.PartInfo{RuleIndex: ruleIdx, Index: i}) require.ErrorIs(t, err, target) } } @@ -1511,55 +1512,55 @@ func testPutTombstoneEC(t *testing.T) { // store parts for i := range parts { - require.NoError(t, s.Put(&parts[i], nil)) + require.NoError(t, s.Put(context.Background(), &parts[i], nil)) } // check before removal - _, err := s.Get(parentAddr) + _, err := s.Get(context.Background(), parentAddr) require.ErrorIs(t, err, ierrors.ErrParentObject) require.ErrorAs(t, err, new(iec.ErrParts)) - _, _, err = s.GetStream(parentAddr) + _, _, err = s.GetStream(context.Background(), parentAddr) require.ErrorIs(t, err, ierrors.ErrParentObject) require.ErrorAs(t, err, new(iec.ErrParts)) - _, err = s.GetBytes(parentAddr) + _, err = s.GetBytes(context.Background(), parentAddr) require.ErrorIs(t, err, ierrors.ErrParentObject) require.ErrorAs(t, err, new(iec.ErrParts)) - _, err = s.GetRange(parentAddr, 0, 1) + _, err = s.GetRange(context.Background(), parentAddr, 0, 1) require.ErrorIs(t, err, ierrors.ErrParentObject) require.ErrorAs(t, err, new(iec.ErrParts)) - hdr, err := s.Head(parentAddr, false) + hdr, err := s.Head(context.Background(), parentAddr, false) require.NoError(t, err) require.Equal(t, parent.CutPayload(), hdr) - hdr, err = s.Head(parentAddr, true) + hdr, err = s.Head(context.Background(), parentAddr, true) require.NoError(t, err) require.Equal(t, parent.CutPayload(), hdr) for i := range parts { - obj, err := s.Get(partAddrs[i]) + obj, err := s.Get(context.Background(), partAddrs[i]) require.NoError(t, err) require.Equal(t, parts[i], *obj) - hdr, rdr, err := s.GetStream(partAddrs[i]) + hdr, rdr, err := s.GetStream(context.Background(), partAddrs[i]) assertGetStreamOK(t, hdr, rdr, err, parts[i]) - b, err := s.GetBytes(partAddrs[i]) + b, err := s.GetBytes(context.Background(), partAddrs[i]) require.NoError(t, err) require.Equal(t, parts[i].Marshal(), b) const off, ln = 3, 12 - b, err = s.GetRange(partAddrs[i], off, ln) + b, err = s.GetRange(context.Background(), partAddrs[i], off, ln) require.NoError(t, err) require.Equal(t, parts[i].Payload()[off:][:ln], b) - hdr, err = s.Head(partAddrs[i], false) + hdr, err = s.Head(context.Background(), partAddrs[i], false) require.NoError(t, err) require.Equal(t, parts[i].CutPayload(), hdr) - hdr, err = s.Head(partAddrs[i], true) + hdr, err = s.Head(context.Background(), partAddrs[i], true) require.NoError(t, err) require.Equal(t, parts[i].CutPayload(), hdr) - h, rdr, err := s.GetECPart(cnr, parent.GetID(), iec.PartInfo{RuleIndex: ruleIdx, Index: i}) + h, rdr, err := s.GetECPart(context.Background(), cnr, parent.GetID(), iec.PartInfo{RuleIndex: ruleIdx, Index: i}) assertGetStreamOK(t, &h, rdr, err, parts[i]) } @@ -1571,7 +1572,7 @@ func testPutTombstoneEC(t *testing.T) { tomb := *generateObjectWithCID(cnr) tomb.AssociateDeleted(parent.GetID()) addAttribute(&tomb, "__NEOFS__EXPIRATION_EPOCH", strconv.Itoa(tombLastEpoch)) - require.NoError(t, s.Put(&tomb, nil)) + require.NoError(t, s.Put(context.Background(), &tomb, nil)) // check marked assertGetErrors(t, apistatus.ErrObjectAlreadyRemoved) @@ -1582,7 +1583,7 @@ func testPutTombstoneEC(t *testing.T) { time.Sleep(2 * gcInterval) - _, err = s.Get(parentAddr) + _, err = s.Get(context.Background(), parentAddr) require.ErrorIs(t, err, apistatus.ErrObjectNotFound) assertGetErrors(t, apistatus.ErrObjectNotFound) diff --git a/pkg/local_object_storage/engine/error_test.go b/pkg/local_object_storage/engine/error_test.go index 60cff2be69..a261a0ede3 100644 --- a/pkg/local_object_storage/engine/error_test.go +++ b/pkg/local_object_storage/engine/error_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "os" "path/filepath" @@ -64,7 +65,7 @@ func TestErrorReporting(t *testing.T) { e.mtx.RUnlock() require.NoError(t, err) - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.NoError(t, err) checkShardState(t, e, id[0], 0, mode.ReadWrite) @@ -74,7 +75,7 @@ func TestErrorReporting(t *testing.T) { t.Cleanup(func() { fixSubDir(t, filepath.Join(dir, "0")) }) for i := uint32(1); i < 3; i++ { - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.Error(t, err) checkShardState(t, e, id[0], i, mode.ReadWrite) checkShardState(t, e, id[1], 0, mode.ReadWrite) @@ -93,7 +94,7 @@ func TestErrorReporting(t *testing.T) { e.mtx.RUnlock() require.NoError(t, err) - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.NoError(t, err) checkShardState(t, e, id[0], 0, mode.ReadWrite) @@ -103,14 +104,14 @@ func TestErrorReporting(t *testing.T) { t.Cleanup(func() { fixSubDir(t, filepath.Join(dir, "0")) }) for i := uint32(1); i < errThreshold; i++ { - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.Error(t, err) checkShardState(t, e, id[0], i, mode.ReadWrite) checkShardState(t, e, id[1], 0, mode.ReadWrite) } for i := range uint32(2) { - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.Error(t, err) checkShardState(t, e, id[0], errThreshold+i, mode.DegradedReadOnly) checkShardState(t, e, id[1], 0, mode.ReadWrite) @@ -145,9 +146,9 @@ func TestBlobstorFailback(t *testing.T) { for i := range objs { addr := objs[i].Address() - _, err := e.Get(addr) + _, err := e.Get(context.Background(), addr) require.NoError(t, err) - _, err = e.GetRange(addr, 0, 0) + _, err = e.GetRange(context.Background(), addr, 0, 0) require.NoError(t, err) } @@ -165,15 +166,15 @@ func TestBlobstorFailback(t *testing.T) { for i := range objs { addr := objs[i].Address() - getObj, err := e.Get(addr) + getObj, err := e.Get(context.Background(), addr) require.NoError(t, err) require.Equal(t, objs[i], getObj) - rngRes, err := e.GetRange(addr, 1, 10) + rngRes, err := e.GetRange(context.Background(), addr, 1, 10) require.NoError(t, err) require.Equal(t, objs[i].Payload()[1:11], rngRes) - _, err = e.GetRange(addr, errSmallSize+10, 1) + _, err = e.GetRange(context.Background(), addr, errSmallSize+10, 1) require.ErrorAs(t, err, &apistatus.ObjectOutOfRange{}) } diff --git a/pkg/local_object_storage/engine/evacuate.go b/pkg/local_object_storage/engine/evacuate.go index fe1229716d..409b763779 100644 --- a/pkg/local_object_storage/engine/evacuate.go +++ b/pkg/local_object_storage/engine/evacuate.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "fmt" "maps" @@ -28,7 +29,7 @@ var errMustHaveTwoShards = errors.New("must have at least 1 spare shard") // (if provided, fails otherwise) which can return its own error to abort // evacuation (or nil to continue). Returns the number of evacuated objects // (which can be non-zero even in case of error). -func (e *StorageEngine) Evacuate(shardIDs []common.ID, ignoreErrors bool, faultHandler func(oid.Address, *object.Object) error) (int, error) { +func (e *StorageEngine) Evacuate(ctx context.Context, shardIDs []common.ID, ignoreErrors bool, faultHandler func(oid.Address, *object.Object) error) (int, error) { sidList := make([]string, len(shardIDs)) for i := range shardIDs { sidList[i] = shardIDs[i].String() @@ -114,7 +115,7 @@ mainLoop: if _, ok := shardMap[shards[j].ID().String()]; ok { continue } - err = e.putToShard(shards[j], addr, obj, nil) + err = e.putToShard(ctx, shards[j], addr, obj, nil) if err == nil || errors.Is(err, errExists) { if !errors.Is(err, errExists) { e.log.Debug("object is moved to another shard", diff --git a/pkg/local_object_storage/engine/evacuate_test.go b/pkg/local_object_storage/engine/evacuate_test.go index 8054d1a5c8..7ed2dc0ed6 100644 --- a/pkg/local_object_storage/engine/evacuate_test.go +++ b/pkg/local_object_storage/engine/evacuate_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "fmt" "path/filepath" @@ -51,7 +52,7 @@ func newEngineEvacuate(t *testing.T, shardNum int, objPerShard int) (*StorageEng for i := 0; ; i++ { objects = append(objects, generateObjectWithCID(cidtest.ID())) - err := e.Put(objects[i], nil) + err := e.Put(context.Background(), objects[i], nil) require.NoError(t, err) res, err := e.shards[ids[len(ids)-1].String()].List() // nolint:staticcheck @@ -72,7 +73,7 @@ func TestEvacuateShard(t *testing.T) { checkHasObjects := func(t *testing.T) { for i := range objects { - _, err := e.Get(objects[i].Address()) + _, err := e.Get(context.Background(), objects[i].Address()) require.NoError(t, err) } } @@ -80,14 +81,14 @@ func TestEvacuateShard(t *testing.T) { checkHasObjects(t) t.Run("must be read-only", func(t *testing.T) { - count, err := e.Evacuate(ids[2:3], false, nil) + count, err := e.Evacuate(context.Background(), ids[2:3], false, nil) require.ErrorIs(t, err, shard.ErrMustBeReadOnly) require.Equal(t, 0, count) }) require.NoError(t, e.shards[evacuateShardID].SetMode(mode.ReadOnly)) - count, err := e.Evacuate(ids[2:3], false, nil) + count, err := e.Evacuate(context.Background(), ids[2:3], false, nil) require.NoError(t, err) require.Equal(t, objPerShard, count) @@ -98,7 +99,7 @@ func TestEvacuateShard(t *testing.T) { checkHasObjects(t) // Calling it again is OK, but all objects are already moved, so no new PUTs should be done. - count, err = e.Evacuate(ids[2:3], false, nil) + count, err = e.Evacuate(context.Background(), ids[2:3], false, nil) require.NoError(t, err) require.Equal(t, 0, count) @@ -139,11 +140,11 @@ func TestEvacuateNetwork(t *testing.T) { require.NoError(t, e.shards[evacuateShardID].SetMode(mode.ReadOnly)) - count, err := e.Evacuate(ids[0:1], false, nil) + count, err := e.Evacuate(context.Background(), ids[0:1], false, nil) require.ErrorIs(t, err, errMustHaveTwoShards) require.Equal(t, 0, count) - count, err = e.Evacuate(ids[0:1], false, acceptOneOf(objects, 2)) + count, err = e.Evacuate(context.Background(), ids[0:1], false, acceptOneOf(objects, 2)) require.ErrorIs(t, err, errReplication) require.Equal(t, 2, count) }) @@ -153,12 +154,12 @@ func TestEvacuateNetwork(t *testing.T) { require.NoError(t, e.shards[ids[0].String()].SetMode(mode.ReadOnly)) require.NoError(t, e.shards[ids[1].String()].SetMode(mode.ReadOnly)) - count, err := e.Evacuate(ids[1:2], false, acceptOneOf(objects, 2)) + count, err := e.Evacuate(context.Background(), ids[1:2], false, acceptOneOf(objects, 2)) require.ErrorIs(t, err, errReplication) require.Equal(t, 2, count) t.Run("no errors", func(t *testing.T) { - count, err := e.Evacuate(ids[1:2], false, acceptOneOf(objects, 3)) + count, err := e.Evacuate(context.Background(), ids[1:2], false, acceptOneOf(objects, 3)) require.NoError(t, err) require.Equal(t, 3, count) }) @@ -179,12 +180,12 @@ func TestEvacuateNetwork(t *testing.T) { require.NoError(t, e.shards[ids[i].String()].SetMode(mode.ReadOnly)) } - count, err := e.Evacuate(evacuateIDs, false, acceptOneOf(objects, totalCount-1)) + count, err := e.Evacuate(context.Background(), evacuateIDs, false, acceptOneOf(objects, totalCount-1)) require.ErrorIs(t, err, errReplication) require.Equal(t, totalCount-1, count) t.Run("no errors", func(t *testing.T) { - count, err = e.Evacuate(evacuateIDs, false, acceptOneOf(objects, totalCount)) + count, err = e.Evacuate(context.Background(), evacuateIDs, false, acceptOneOf(objects, totalCount)) require.NoError(t, err) require.Equal(t, totalCount, count) }) diff --git a/pkg/local_object_storage/engine/gc_test.go b/pkg/local_object_storage/engine/gc_test.go index 6b8b6217cc..08fe13d7a5 100644 --- a/pkg/local_object_storage/engine/gc_test.go +++ b/pkg/local_object_storage/engine/gc_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "path/filepath" "strconv" @@ -87,10 +88,10 @@ func TestChildrenExpiration(t *testing.T) { link.SetChildren(child1ID, child2ID, child3ID) link.SetSplitID(splitID) - require.NoError(t, e.Put(child1, nil)) - require.NoError(t, e.Put(child2, nil)) - require.NoError(t, e.Put(child3, nil)) - require.NoError(t, e.Put(link, nil)) + require.NoError(t, e.Put(context.Background(), child1, nil)) + require.NoError(t, e.Put(context.Background(), child2, nil)) + require.NoError(t, e.Put(context.Background(), child3, nil)) + require.NoError(t, e.Put(context.Background(), link, nil)) tickEpoch(es, e) @@ -135,10 +136,10 @@ func TestChildrenExpiration(t *testing.T) { linkObj.CalculateAndSetPayloadChecksum() require.NoError(t, linkObj.CalculateAndSetID()) - require.NoError(t, e.Put(child1, nil)) - require.NoError(t, e.Put(child2, nil)) - require.NoError(t, e.Put(child3, nil)) - require.NoError(t, e.Put(&linkObj, nil)) + require.NoError(t, e.Put(context.Background(), child1, nil)) + require.NoError(t, e.Put(context.Background(), child2, nil)) + require.NoError(t, e.Put(context.Background(), child3, nil)) + require.NoError(t, e.Put(context.Background(), &linkObj, nil)) tickEpoch(es, e) @@ -155,7 +156,7 @@ func checkObjectsAsyncRemoval(t *testing.T, e *StorageEngine, cnr cid.ID, objs . for _, obj := range objs { addr.SetObject(obj) - _, err := e.Get(addr) + _, err := e.Get(context.Background(), addr) require.ErrorAs(t, err, new(statusSDK.ObjectNotFound)) } } @@ -191,7 +192,7 @@ func TestGC(t *testing.T) { // t.Run("expired object", func(t *testing.T) { obj := generateObjectWithCID(cnr) addExpirationAttribute(obj, es.CurrentEpoch()) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) tickEpoch(es, e) @@ -200,13 +201,13 @@ func TestGC(t *testing.T) { // t.Run("object with lock - prevents deletion until lock expires", func(t *testing.T) { obj = generateObjectWithCID(cnr) addExpirationAttribute(obj, es.CurrentEpoch()) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) objAddr := obj.Address() lockObj := generateObjectWithCID(cnr) lockObj.AssociateLocked(obj.GetID()) addExpirationAttribute(lockObj, es.CurrentEpoch()+1) // lock expires after object - require.NoError(t, e.Put(lockObj, nil)) + require.NoError(t, e.Put(context.Background(), lockObj, nil)) tickEpoch(es, e) @@ -214,7 +215,7 @@ func TestGC(t *testing.T) { time.Sleep(200 * time.Millisecond) // object must stay because it's locked - _, err := e.Get(objAddr) + _, err := e.Get(context.Background(), objAddr) require.NoError(t, err) tickEpoch(es, e) @@ -226,7 +227,7 @@ func TestGC(t *testing.T) { tomb := generateObjectWithCID(cnr) tomb.AssociateDeleted(oidtest.ID()) addExpirationAttribute(tomb, es.CurrentEpoch()) - require.NoError(t, e.Put(tomb, nil)) + require.NoError(t, e.Put(context.Background(), tomb, nil)) tickEpoch(es, e) @@ -234,7 +235,7 @@ func TestGC(t *testing.T) { // t.Run("object inhume by tombstone", func(t *testing.T) { obj = generateObjectWithCID(cnr) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) tomb = generateObjectWithCID(cnr) var a object.Attribute @@ -245,9 +246,9 @@ func TestGC(t *testing.T) { objAddr = obj.Address() tomb.AssociateDeleted(obj.GetID()) - require.NoError(t, e.Put(tomb, nil)) + require.NoError(t, e.Put(context.Background(), tomb, nil)) - _, err = e.Get(objAddr) + _, err = e.Get(context.Background(), objAddr) require.ErrorIs(t, err, statusSDK.ErrObjectAlreadyRemoved) tickEpoch(es, e) @@ -256,13 +257,13 @@ func TestGC(t *testing.T) { // t.Run("object associated with expired tombstone", func(t *testing.T) { obj = generateObjectWithCID(cnr) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) tomb = generateObjectWithCID(cnr) tomb.AssociateDeleted(obj.GetID()) addExpirationAttribute(tomb, es.CurrentEpoch()) - require.NoError(t, e.Put(tomb, nil)) + require.NoError(t, e.Put(context.Background(), tomb, nil)) - _, err = e.Get(obj.Address()) + _, err = e.Get(context.Background(), obj.Address()) require.ErrorIs(t, err, statusSDK.ErrObjectAlreadyRemoved) tickEpoch(es, e) @@ -272,13 +273,13 @@ func TestGC(t *testing.T) { // t.Run("object with tombstone expires", func(t *testing.T) { obj = generateObjectWithCID(cnr) addExpirationAttribute(obj, es.CurrentEpoch()) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) objAddr = obj.Address() tomb = generateObjectWithCID(cnr) tomb.AssociateDeleted(obj.GetID()) addExpirationAttribute(tomb, es.CurrentEpoch()+1) // tombstone expires after object - require.NoError(t, e.Put(tomb, nil)) + require.NoError(t, e.Put(context.Background(), tomb, nil)) tickEpoch(es, e) @@ -286,9 +287,9 @@ func TestGC(t *testing.T) { time.Sleep(200 * time.Millisecond) // object covered by tombstone - _, err = e.Get(objAddr) + _, err = e.Get(context.Background(), objAddr) require.ErrorIs(t, err, statusSDK.ErrObjectAlreadyRemoved) - _, err = e.Get(tomb.Address()) + _, err = e.Get(context.Background(), tomb.Address()) require.NoError(t, err) tickEpoch(es, e) @@ -358,10 +359,10 @@ func TestSplitObjectExpirationWithoutLink(t *testing.T) { } for i := range children { - require.NoError(t, e.Put(children[i], nil)) + require.NoError(t, e.Put(context.Background(), children[i], nil)) } - _, err = e.Get(parentAddr) + _, err = e.Get(context.Background(), parentAddr) var splitErr *object.SplitInfoError require.ErrorAs(t, err, &splitErr) // Do not put link, so parent will have SplitInfo without link @@ -450,15 +451,15 @@ func TestSplitObjectExpirationWithLinkNotFound(t *testing.T) { linkAddr := linkObj.Address() // Put link object and all children - require.NoError(t, e.Put(&linkObj, nil)) + require.NoError(t, e.Put(context.Background(), &linkObj, nil)) for i := range children { - require.NoError(t, e.Put(children[i], nil)) + require.NoError(t, e.Put(context.Background(), children[i], nil)) } - _, err = e.Get(linkAddr) + _, err = e.Get(context.Background(), linkAddr) require.NoError(t, err) - _, err = e.Get(parentAddr) + _, err = e.Get(context.Background(), parentAddr) var splitErr *object.SplitInfoError require.ErrorAs(t, err, &splitErr) require.Equal(t, linkObj.GetID(), splitErr.SplitInfo().GetLink()) @@ -468,10 +469,10 @@ func TestSplitObjectExpirationWithLinkNotFound(t *testing.T) { // Now delete the link object to simulate missing link scenario require.NoError(t, fstr.Delete(linkAddr)) - _, err = e.Get(linkAddr) + _, err = e.Get(context.Background(), linkAddr) require.ErrorIs(t, err, statusSDK.ErrObjectNotFound) - _, err = e.Get(parentAddr) + _, err = e.Get(context.Background(), parentAddr) require.ErrorAs(t, err, &splitErr) require.Equal(t, linkObj.GetID(), splitErr.SplitInfo().GetLink()) // Pretends to be here, but not in fact. require.Equal(t, childIDs[len(childIDs)-1], splitErr.SplitInfo().GetLastPart()) diff --git a/pkg/local_object_storage/engine/get.go b/pkg/local_object_storage/engine/get.go index 8413a60657..2054ab1e89 100644 --- a/pkg/local_object_storage/engine/get.go +++ b/pkg/local_object_storage/engine/get.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "io" @@ -26,7 +27,7 @@ import ( // // If referenced object is a parent of some stored EC parts, Get returns // [ierrors.ErrParentObject] wrapping [iec.ErrParts]. -func (e *StorageEngine) Get(addr oid.Address) (*object.Object, error) { +func (e *StorageEngine) Get(_ context.Context, addr oid.Address) (*object.Object, error) { if e.metrics != nil { defer elapsed(e.metrics.AddGetDuration)() } @@ -145,7 +146,7 @@ func (e *StorageEngine) get(addr oid.Address, shardFunc func(s *shard.Shard, ign // // If referenced object is a parent of some stored EC parts, GetBytes returns // [ierrors.ErrParentObject] wrapping [iec.ErrParts]. -func (e *StorageEngine) GetBytes(addr oid.Address) ([]byte, error) { +func (e *StorageEngine) GetBytes(_ context.Context, addr oid.Address) ([]byte, error) { e.blockMtx.RLock() defer e.blockMtx.RUnlock() @@ -182,7 +183,7 @@ func (e *StorageEngine) GetBytes(addr oid.Address) ([]byte, error) { // // If referenced object is a parent of some stored EC parts, GetStream returns // [ierrors.ErrParentObject] wrapping [iec.ErrParts]. -func (e *StorageEngine) GetStream(addr oid.Address) (*object.Object, io.ReadCloser, error) { +func (e *StorageEngine) GetStream(_ context.Context, addr oid.Address) (*object.Object, io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddGetStreamDuration)() } @@ -215,15 +216,15 @@ func (e *StorageEngine) GetStream(addr oid.Address) (*object.Object, io.ReadClos // // If the range is out of payload bounds, GetRangeStream returns // [apistatus.ErrObjectOutOfRange]. -func (e *StorageEngine) GetRangeStream(addr oid.Address, off, ln uint64) (io.ReadCloser, error) { +func (e *StorageEngine) GetRangeStream(ctx context.Context, addr oid.Address, off, ln uint64) (io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddGetRangeStreamDuration)() } - return e.getRangeStream(addr, off, ln) + return e.getRangeStream(ctx, addr, off, ln) } -func (e *StorageEngine) getRangeStream(addr oid.Address, off, ln uint64) (io.ReadCloser, error) { +func (e *StorageEngine) getRangeStream(_ context.Context, addr oid.Address, off, ln uint64) (io.ReadCloser, error) { e.blockMtx.RLock() defer e.blockMtx.RUnlock() @@ -256,7 +257,7 @@ func (e *StorageEngine) getRangeStream(addr oid.Address, off, ln uint64) (io.Rea // // If object is a split-parent, ReadObject returns [object.SplitInfoError] with // all relations recorded in e. -func (e *StorageEngine) ReadObject(addr oid.Address, buf []byte) (int, io.ReadCloser, error) { +func (e *StorageEngine) ReadObject(_ context.Context, addr oid.Address, buf []byte) (int, io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddReadObjectDuration)() } @@ -285,7 +286,7 @@ func (e *StorageEngine) ReadObject(addr oid.Address, buf []byte) (int, io.ReadCl // // If given range is out of payload bounds, ReadPayloadRange returns // [apistatus.ErrObjectOutOfRange]. -func (e *StorageEngine) ReadPayloadRange(addr oid.Address, off, ln uint64, hdrBuf []byte) (io.ReadCloser, error) { +func (e *StorageEngine) ReadPayloadRange(_ context.Context, addr oid.Address, off, ln uint64, hdrBuf []byte) (io.ReadCloser, error) { if e.metrics != nil { defer elapsed(e.metrics.AddReadPayloadRangeDuration)() } diff --git a/pkg/local_object_storage/engine/get_test.go b/pkg/local_object_storage/engine/get_test.go index 37173640d4..f57f3a72bd 100644 --- a/pkg/local_object_storage/engine/get_test.go +++ b/pkg/local_object_storage/engine/get_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "io" "testing" @@ -16,10 +17,10 @@ func TestStorageEngine_GetBytes(t *testing.T) { objBin := obj.Marshal() - err := e.Put(obj, nil) + err := e.Put(context.Background(), obj, nil) require.NoError(t, err) - b, err := e.GetBytes(addr) + b, err := e.GetBytes(context.Background(), addr) require.NoError(t, err) require.Equal(t, objBin, b) } @@ -29,10 +30,10 @@ func TestStorageEngine_GetStream(t *testing.T) { obj := generateObjectWithCID(cidtest.ID()) addr := obj.Address() - err := e.Put(obj, nil) + err := e.Put(context.Background(), obj, nil) require.NoError(t, err) - header, reader, err := e.GetStream(addr) + header, reader, err := e.GetStream(context.Background(), addr) assertGetStreamOK(t, header, reader, err, *obj) } diff --git a/pkg/local_object_storage/engine/head.go b/pkg/local_object_storage/engine/head.go index 15e4f95c2d..8986748e9d 100644 --- a/pkg/local_object_storage/engine/head.go +++ b/pkg/local_object_storage/engine/head.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard" @@ -22,7 +23,7 @@ import ( // Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object was inhumed. // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) Head(addr oid.Address, raw bool) (*object.Object, error) { +func (e *StorageEngine) Head(_ context.Context, addr oid.Address, raw bool) (*object.Object, error) { if e.metrics != nil { defer elapsed(e.metrics.AddHeadDuration)() } @@ -49,7 +50,7 @@ func (e *StorageEngine) Head(addr oid.Address, raw bool) (*object.Object, error) // If object is a split-parent, behavior depends on raw flag. If set, ReadHeader // returns [object.SplitInfoError] with all relations recorded in e. If unset, // ReadHeader reads header of the requested object from the child one into buf. -func (e *StorageEngine) ReadHeader(addr oid.Address, raw bool, buf []byte) (int, error) { +func (e *StorageEngine) ReadHeader(_ context.Context, addr oid.Address, raw bool, buf []byte) (int, error) { if e.metrics != nil { defer elapsed(e.metrics.AddReadHeaderDuration)() } diff --git a/pkg/local_object_storage/engine/head_test.go b/pkg/local_object_storage/engine/head_test.go index 5408c6037b..baeb75f6ee 100644 --- a/pkg/local_object_storage/engine/head_test.go +++ b/pkg/local_object_storage/engine/head_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "testing" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" @@ -52,7 +53,7 @@ func TestHeadRaw(t *testing.T) { require.NoError(t, err) // head with raw flag should return SplitInfoError - _, err = e.Head(parentAddr, true) + _, err = e.Head(context.Background(), parentAddr, true) require.Error(t, err) var si *object.SplitInfoError diff --git a/pkg/local_object_storage/engine/inhume.go b/pkg/local_object_storage/engine/inhume.go index fe85530574..4ca7d29730 100644 --- a/pkg/local_object_storage/engine/inhume.go +++ b/pkg/local_object_storage/engine/inhume.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" iec "github.com/nspcc-dev/neofs-node/internal/ec" @@ -22,7 +23,7 @@ var errInhumeFailure = errors.New("inhume operation failed") // There is no any LOCKs, forced GC marks and any relations checks, // every object that belongs to a provided container will be marked // as a removed one. -func (e *StorageEngine) InhumeContainer(cID cid.ID) error { +func (e *StorageEngine) InhumeContainer(_ context.Context, cID cid.ID) error { e.blockMtx.RLock() defer e.blockMtx.RUnlock() @@ -222,7 +223,7 @@ func (e *StorageEngine) collectChildrenWithoutLink(addr oid.Address, si *object. } // IsLocked checks whether an object is locked according to StorageEngine's state. -func (e *StorageEngine) IsLocked(addr oid.Address) (bool, error) { +func (e *StorageEngine) IsLocked(_ context.Context, addr oid.Address) (bool, error) { e.blockMtx.RLock() defer e.blockMtx.RUnlock() diff --git a/pkg/local_object_storage/engine/inhume_test.go b/pkg/local_object_storage/engine/inhume_test.go index ebf1f7cd98..1c05c66398 100644 --- a/pkg/local_object_storage/engine/inhume_test.go +++ b/pkg/local_object_storage/engine/inhume_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "strconv" "testing" @@ -39,7 +40,7 @@ func TestStorageEngine_Inhume(t *testing.T) { e := testNewEngineWithShardNum(t, 1) defer e.Close() - err := e.Put(parent, nil) + err := e.Put(context.Background(), parent, nil) require.NoError(t, err) tomb := generateObjectWithCID(parent.GetContainerID()) @@ -50,10 +51,10 @@ func TestStorageEngine_Inhume(t *testing.T) { tomb.SetAttributes(a) tomb.AssociateDeleted(idParent) - err = e.Put(tomb, nil) + err = e.Put(context.Background(), tomb, nil) require.NoError(t, err) - addrs, err := e.selectOld(cnr, fs) + addrs, err := e.selectOld(context.Background(), cnr, fs) require.NoError(t, err) require.Empty(t, addrs) }) @@ -79,26 +80,26 @@ func TestStorageEngine_Inhume(t *testing.T) { tomb.SetAttributes(a) tomb.AssociateDeleted(idParent) - err = e.Put(tomb, nil) + err = e.Put(context.Background(), tomb, nil) require.NoError(t, err) - _, err = e.Get(parent.Address()) + _, err = e.Get(context.Background(), parent.Address()) require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) - _, err = e.Get(child.Address()) + _, err = e.Get(context.Background(), child.Address()) require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) - _, err = e.Get(link.Address()) + _, err = e.Get(context.Background(), link.Address()) require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) t.Run("empty search should return ts", func(t *testing.T) { - addrs, err := e.selectOld(cnr, object.SearchFilters{}) + addrs, err := e.selectOld(context.Background(), cnr, object.SearchFilters{}) require.NoError(t, err) require.Equal(t, []oid.Address{tomb.Address()}, addrs) }) t.Run("root search should fail", func(t *testing.T) { - addrs, err := e.selectOld(cnr, fs) + addrs, err := e.selectOld(context.Background(), cnr, fs) require.NoError(t, err) require.Empty(t, addrs) }) @@ -108,18 +109,18 @@ func TestStorageEngine_Inhume(t *testing.T) { addr.SetContainer(cnr) addr.SetObject(idChild) - _, err = e.Get(addr) + _, err = e.Get(context.Background(), addr) require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved)) linkID := link.GetID() addr.SetObject(linkID) - _, err = e.Get(addr) + _, err = e.Get(context.Background(), addr) require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved)) }) t.Run("parent get should claim deletion", func(t *testing.T) { - _, err = e.Get(parent.Address()) + _, err = e.Get(context.Background(), parent.Address()) require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved)) }) }) @@ -147,7 +148,7 @@ func TestStorageEngine_Inhume(t *testing.T) { _, err = wrongShard.Get(addr, false) require.NoError(t, err) - err = e.Delete(addr) + err = e.Delete(context.Background(), addr) require.NoError(t, err) // object was on the wrong (according to hash sorting) shard but is removed anyway @@ -161,11 +162,11 @@ func TestStorageEngine_Inhume(t *testing.T) { e := testNewEngineWithShardNum(t, 3) defer e.Close() - err := e.Delete(addr) + err := e.Delete(context.Background(), addr) require.NoError(t, err) // object is marked as garbage but marking it again should not be a problem - err = e.Delete(addr) + err = e.Delete(context.Background(), addr) require.NoError(t, err) }) } diff --git a/pkg/local_object_storage/engine/list.go b/pkg/local_object_storage/engine/list.go index 72371e03b9..a3d6ec30d5 100644 --- a/pkg/local_object_storage/engine/list.go +++ b/pkg/local_object_storage/engine/list.go @@ -1,6 +1,8 @@ package engine import ( + "context" + objectcore "github.com/nspcc-dev/neofs-node/pkg/core/object" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" @@ -50,7 +52,7 @@ func (c *Cursor) ObjectID() oid.ID { // // Returns ErrEndOfListing if there are no more objects to return or count // parameter set to zero. -func (e *StorageEngine) ListWithCursor(count uint32, cursor *Cursor, attrs ...string) ([]objectcore.AddressWithAttributes, *Cursor, error) { +func (e *StorageEngine) ListWithCursor(_ context.Context, count uint32, cursor *Cursor, attrs ...string) ([]objectcore.AddressWithAttributes, *Cursor, error) { if e.metrics != nil { defer elapsed(e.metrics.AddListObjectsDuration)() } diff --git a/pkg/local_object_storage/engine/list_test.go b/pkg/local_object_storage/engine/list_test.go index 6d880088a1..44551dba5a 100644 --- a/pkg/local_object_storage/engine/list_test.go +++ b/pkg/local_object_storage/engine/list_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "fmt" "slices" @@ -34,7 +35,7 @@ func TestListWithCursor(t *testing.T) { containerID := cidtest.ID() obj := generateObjectWithCID(containerID) - err := e.Put(obj, nil) + err := e.Put(context.Background(), obj, nil) require.NoError(t, err) expected = append(expected, objectcore.AddressWithAttributes{Type: object.TypeRegular, Address: obj.Address()}) } @@ -43,20 +44,20 @@ func TestListWithCursor(t *testing.T) { return a.Address.Compare(b.Address) }) - addrs, cursor, err := e.ListWithCursor(1, nil) + addrs, cursor, err := e.ListWithCursor(context.Background(), 1, nil) require.NoError(t, err) require.NotEmpty(t, addrs) got = append(got, addrs...) for range total - 1 { - addrs, cursor, err = e.ListWithCursor(1, cursor) + addrs, cursor, err = e.ListWithCursor(context.Background(), 1, cursor) if errors.Is(err, ErrEndOfListing) { break } got = append(got, addrs...) } - _, _, err = e.ListWithCursor(1, cursor) + _, _, err = e.ListWithCursor(context.Background(), 1, cursor) require.ErrorIs(t, err, ErrEndOfListing) got = stripShardIDs(got) @@ -105,7 +106,7 @@ func TestListWithCursor(t *testing.T) { t.Run(fmt.Sprintf("shard=%d", shardNum), func(t *testing.T) { s := testNewEngineWithShardNum(t, shardNum) for i := range objs { - require.NoError(t, s.Put(&objs[i], nil)) + require.NoError(t, s.Put(context.Background(), &objs[i], nil)) } for _, count := range []uint32{ @@ -136,10 +137,10 @@ func TestListWithCursor_Dedup(t *testing.T) { require.NoError(t, s1.Put(obj, nil)) require.NoError(t, s2.Put(obj, nil)) - res, cursor, err := e.ListWithCursor(2, nil) + res, cursor, err := e.ListWithCursor(context.Background(), 2, nil) require.NoError(t, err) - _, _, err = e.ListWithCursor(2, cursor) + _, _, err = e.ListWithCursor(context.Background(), 2, cursor) require.ErrorIs(t, err, ErrEndOfListing) require.Len(t, res, 1) @@ -161,7 +162,7 @@ func collectListWithCursor(t *testing.T, s *StorageEngine, count uint32, attrs . var crs *Cursor var err error for { - next, crs, err = s.ListWithCursor(count, crs, attrs...) + next, crs, err = s.ListWithCursor(context.Background(), count, crs, attrs...) collected = append(collected, next...) if errors.Is(err, ErrEndOfListing) { return collected diff --git a/pkg/local_object_storage/engine/lock_test.go b/pkg/local_object_storage/engine/lock_test.go index 966030cdf2..93e90e8ef0 100644 --- a/pkg/local_object_storage/engine/lock_test.go +++ b/pkg/local_object_storage/engine/lock_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "path/filepath" "strconv" @@ -70,21 +71,21 @@ func TestLockUserScenario(t *testing.T) { tombForLockObj.AssociateDeleted(lockerID) // 1. - err = e.Put(obj, nil) + err = e.Put(context.Background(), obj, nil) require.NoError(t, err) // 2. lockerObj.AssociateLocked(id) - err = e.Put(lockerObj, nil) + err = e.Put(context.Background(), lockerObj, nil) require.NoError(t, err) // 3. - err = e.Put(tombObj, nil) + err = e.Put(context.Background(), tombObj, nil) require.ErrorAs(t, err, new(apistatus.ObjectLocked)) // 4. - err = e.Put(tombForLockObj, nil) + err = e.Put(context.Background(), tombForLockObj, nil) require.ErrorIs(t, err, meta.ErrLockObjectRemoval) // 5. @@ -93,7 +94,7 @@ func TestLockUserScenario(t *testing.T) { // delay for GC time.Sleep(time.Second) - err = e.Put(tombObj, nil) + err = e.Put(context.Background(), tombObj, nil) require.NoError(t, err) } @@ -120,7 +121,7 @@ func TestLockExpiration(t *testing.T) { // 1. obj := generateObjectWithCID(cnr) - err = e.Put(obj, nil) + err = e.Put(context.Background(), obj, nil) require.NoError(t, err) // 2. @@ -132,14 +133,14 @@ func TestLockExpiration(t *testing.T) { lock.SetAttributes(a) lock.AssociateLocked(obj.GetID()) - err = e.Put(lock, nil) + err = e.Put(context.Background(), lock, nil) require.NoError(t, err) var tombForObj = generateObjectWithCID(cnr) tombForObj.SetAttributes(a) tombForObj.AssociateDeleted(obj.GetID()) - err = e.Put(tombForObj, nil) + err = e.Put(context.Background(), tombForObj, nil) require.ErrorAs(t, err, new(apistatus.ObjectLocked)) // 3. @@ -150,7 +151,7 @@ func TestLockExpiration(t *testing.T) { time.Sleep(time.Second) // 4. - err = e.Put(tombForObj, nil) + err = e.Put(context.Background(), tombForObj, nil) require.NoError(t, err) } @@ -175,14 +176,14 @@ func TestLockForceRemoval(t *testing.T) { // 1. obj := generateObjectWithCID(cnr) - err = e.Put(obj, nil) + err = e.Put(context.Background(), obj, nil) require.NoError(t, err) // 2. lock := generateObjectWithCID(cnr) lock.AssociateLocked(obj.GetID()) - err = e.Put(lock, nil) + err = e.Put(context.Background(), lock, nil) require.NoError(t, err) // 3. @@ -195,15 +196,15 @@ func TestLockForceRemoval(t *testing.T) { tombForLockObj.SetAttributes(a) tombForLockObj.AssociateDeleted(obj.GetID()) - err = e.Put(tombForLockObj, nil) + err = e.Put(context.Background(), tombForLockObj, nil) require.ErrorAs(t, err, new(apistatus.ObjectLocked)) // 4. - err = e.Delete(lock.Address()) + err = e.Delete(context.Background(), lock.Address()) require.NoError(t, err) // 5. - err = e.Put(tombForLockObj, nil) + err = e.Put(context.Background(), tombForLockObj, nil) require.NoError(t, err) } @@ -274,32 +275,32 @@ func testLockRemoved(t *testing.T, shardNum int) { assertLockErr func(t *testing.T, err error) }{ {name: "with target and tombstone", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) - require.NoError(t, s.Put(&tomb, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) + require.NoError(t, s.Put(context.Background(), &tomb, nil)) }, assertLockErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "tombstone without target", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&tomb, nil)) + require.NoError(t, s.Put(context.Background(), &tomb, nil)) }, assertLockErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "with target and tombstone", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) - err := s.Put(&tomb, nil) + require.NoError(t, s.Put(context.Background(), &obj, nil)) + err := s.Put(context.Background(), &tomb, nil) require.NoError(t, err) }, assertLockErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "tombstone without target", preset: func(t *testing.T, s *StorageEngine) { - err := s.Put(&tomb, nil) + err := s.Put(context.Background(), &tomb, nil) require.NoError(t, err) }, assertLockErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "with target and GC mark", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) - err := s.Delete(objAddr) + require.NoError(t, s.Put(context.Background(), &obj, nil)) + err := s.Delete(context.Background(), objAddr) require.NoError(t, err) }}, } { @@ -308,10 +309,10 @@ func testLockRemoved(t *testing.T, shardNum int) { tc.preset(t, s) - lockErr := s.Put(lockObj, nil) - locked, lockedErr := s.IsLocked(objAddr) - _, lockHeadErr := s.Head(lockAddr, false) - _, lockGetErr := s.Get(lockAddr) + lockErr := s.Put(context.Background(), lockObj, nil) + locked, lockedErr := s.IsLocked(context.Background(), objAddr) + _, lockHeadErr := s.Head(context.Background(), lockAddr, false) + _, lockGetErr := s.Get(context.Background(), lockAddr) if tc.assertLockErr != nil { tc.assertLockErr(t, lockErr) @@ -393,11 +394,11 @@ func TestSplitObjectLockExpiration(t *testing.T) { link.SetChildren(childIDs...) for i := range children { - require.NoError(t, e.Put(children[i], nil)) + require.NoError(t, e.Put(context.Background(), children[i], nil)) } - require.NoError(t, e.Put(link, nil)) + require.NoError(t, e.Put(context.Background(), link, nil)) - _, err := e.Get(parentAddr) + _, err := e.Get(context.Background(), parentAddr) var splitErr *object.SplitInfoError require.ErrorAs(t, err, &splitErr) require.Equal(t, splitID, splitErr.SplitInfo().SplitID()) @@ -407,23 +408,23 @@ func TestSplitObjectLockExpiration(t *testing.T) { lockObj.AssociateLocked(parentID) addExpirationAttribute(lockObj, es.CurrentEpoch()+1) - require.NoError(t, e.Put(lockObj, nil)) + require.NoError(t, e.Put(context.Background(), lockObj, nil)) - l, err := e.IsLocked(parentAddr) + l, err := e.IsLocked(context.Background(), parentAddr) require.NoError(t, err) require.True(t, l) // Advance epoch but keep lock valid tickEpoch(es, e) - l, err = e.IsLocked(parentAddr) + l, err = e.IsLocked(context.Background(), parentAddr) require.NoError(t, err) require.True(t, l) // Advance epoch again - now lock should expire tickEpoch(es, e) - l, err = e.IsLocked(parentAddr) + l, err = e.IsLocked(context.Background(), parentAddr) require.NoError(t, err) require.False(t, l) }) @@ -462,24 +463,24 @@ func TestSimpleLockExpiration(t *testing.T) { lock.AssociateLocked(objID) addExpirationAttribute(lock, es.CurrentEpoch()+1) - require.NoError(t, e.Put(obj, nil)) - require.NoError(t, e.Put(lock, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) + require.NoError(t, e.Put(context.Background(), lock, nil)) - locked, err := e.IsLocked(objAddr) + locked, err := e.IsLocked(context.Background(), objAddr) require.NoError(t, err) require.True(t, locked) // Advance epoch but keep lock valid tickEpoch(es, e) - locked, err = e.IsLocked(objAddr) + locked, err = e.IsLocked(context.Background(), objAddr) require.NoError(t, err) require.True(t, locked) // Advance epoch again - now lock should expire tickEpoch(es, e) - locked, err = e.IsLocked(objAddr) + locked, err = e.IsLocked(context.Background(), objAddr) require.NoError(t, err) require.False(t, locked) } diff --git a/pkg/local_object_storage/engine/put.go b/pkg/local_object_storage/engine/put.go index e5c926cab8..4b091cf08e 100644 --- a/pkg/local_object_storage/engine/put.go +++ b/pkg/local_object_storage/engine/put.go @@ -36,7 +36,7 @@ var ( // Returns [apistatus.ErrObjectAlreadyRemoved] if obj is of [object.TypeLock] // type and there is an object of [object.TypeTombstone] type associated with // the same target. -func (e *StorageEngine) Put(obj *object.Object, objBin []byte) error { +func (e *StorageEngine) Put(ctx context.Context, obj *object.Object, objBin []byte) error { if e.metrics != nil { defer elapsed(e.metrics.AddPutDuration)() } @@ -61,7 +61,7 @@ func (e *StorageEngine) Put(obj *object.Object, objBin []byte) error { switch obj.Type() { case object.TypeTombstone, object.TypeLock, object.TypeLink: // Broadcast object to ALL shards to ensure availability everywhere. - return e.broadcastObject(obj, objBin) + return e.broadcastObject(ctx, obj, objBin) default: } @@ -81,7 +81,7 @@ func (e *StorageEngine) Put(obj *object.Object, objBin []byte) error { } for _, sh := range shs { - err = e.putToShard(sh, addr, obj, objBin) + err = e.putToShard(ctx, sh, addr, obj, objBin) if err == nil || errors.Is(err, errExists) { return nil } @@ -102,16 +102,16 @@ func (e *StorageEngine) Put(obj *object.Object, objBin []byte) error { // putToShard puts object to sh. // Returns error from shard put or errOverloaded (when shard pool can't accept // the task) or errExists (if object is already stored there). -func (e *StorageEngine) putToShard(sh shardWrapper, addr oid.Address, obj *object.Object, objBin []byte) error { +func (e *StorageEngine) putToShard(ctx context.Context, sh shardWrapper, addr oid.Address, obj *object.Object, objBin []byte) error { var ( - exitCh = make(chan error) - ctx, cancel = context.WithTimeout(context.TODO(), e.objectPutTimeout+time.Millisecond) // 1ms to avoid zero value. + exitCh = make(chan error) + pCtx, pCancel = context.WithTimeout(ctx, e.objectPutTimeout+time.Millisecond) // 1ms to avoid zero value. ) - defer cancel() + defer pCancel() select { case sh.putCh <- putTask{addr: addr, obj: obj, objBin: objBin, retCh: exitCh}: - case <-ctx.Done(): + case <-pCtx.Done(): return errOverloaded } @@ -160,7 +160,7 @@ func (sh *shardWrapper) shardPutThread() { } // broadcastObject stores object on ALL shards to ensure it's available everywhere. -func (e *StorageEngine) broadcastObject(obj *object.Object, objBin []byte) error { +func (e *StorageEngine) broadcastObject(ctx context.Context, obj *object.Object, objBin []byte) error { var ( allShards = e.unsortedShards() addr = obj.Address() @@ -176,7 +176,7 @@ func (e *StorageEngine) broadcastObject(obj *object.Object, objBin []byte) error zap.Int("shard_count", len(allShards))) for _, sh := range allShards { - err := e.putToShard(sh, addr, obj, objBin) + err := e.putToShard(ctx, sh, addr, obj, objBin) if err == nil || errors.Is(err, errExists) { goodShards = append(goodShards, sh) if errors.Is(err, errExists) { diff --git a/pkg/local_object_storage/engine/put_test.go b/pkg/local_object_storage/engine/put_test.go index 92ddf2779a..9b7145aea9 100644 --- a/pkg/local_object_storage/engine/put_test.go +++ b/pkg/local_object_storage/engine/put_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "strconv" "testing" @@ -34,14 +35,14 @@ func TestStorageEngine_PutBinary(t *testing.T) { e, _, _ := newEngine(t, t.TempDir()) - err := e.Put(&obj, objBin) + err := e.Put(context.Background(), &obj, objBin) require.NoError(t, err) - gotObj, err := e.Get(addr) + gotObj, err := e.Get(context.Background(), addr) require.NoError(t, err) require.Equal(t, &obj, gotObj) - b, err := e.GetBytes(addr) + b, err := e.GetBytes(context.Background(), addr) require.NoError(t, err) require.Equal(t, objBin, b) @@ -49,14 +50,14 @@ func TestStorageEngine_PutBinary(t *testing.T) { addr.SetObject(oidtest.ID()) obj.SetID(addr.Object()) // to avoid 'already exists' outcome invalidObjBin := []byte("definitely not an object") - err = e.Put(&obj, invalidObjBin) + err = e.Put(context.Background(), &obj, invalidObjBin) require.NoError(t, err) - b, err = e.GetBytes(addr) + b, err = e.GetBytes(context.Background(), addr) require.NoError(t, err) require.Equal(t, invalidObjBin, b) - _, err = e.Get(addr) + _, err = e.Get(context.Background(), addr) require.Error(t, err) } @@ -111,15 +112,15 @@ func testPutLock(t *testing.T, shardNum int) { default: } - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) - require.ErrorIs(t, s.Put(&lock, nil), apistatus.ErrLockNonRegularObject) + require.ErrorIs(t, s.Put(context.Background(), &lock, nil), apistatus.ErrLockNonRegularObject) - locked, err := s.IsLocked(objAddr) + locked, err := s.IsLocked(context.Background(), objAddr) require.NoError(t, err) require.False(t, locked) - _, err = s.Get(lockAddr) + _, err = s.Get(context.Background(), lockAddr) require.ErrorIs(t, err, apistatus.ErrObjectNotFound) } }) @@ -149,7 +150,7 @@ func testPutLock(t *testing.T, shardNum int) { Index: i, }) require.NoError(t, err) - require.NoError(t, s.Put(&partObj, nil)) + require.NoError(t, s.Put(context.Background(), &partObj, nil)) } var lock object.Object @@ -159,9 +160,9 @@ func testPutLock(t *testing.T, shardNum int) { require.NoError(t, lock.SetVerificationFields(creator)) - require.NoError(t, s.Put(&lock, nil)) + require.NoError(t, s.Put(context.Background(), &lock, nil)) - locked, err := s.IsLocked(parentAddr) + locked, err := s.IsLocked(context.Background(), parentAddr) require.NoError(t, err) require.True(t, locked) @@ -181,23 +182,23 @@ func testPutLock(t *testing.T, shardNum int) { }{ {name: "no target", preset: func(t *testing.T, s *StorageEngine) {}}, {name: "with target", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) }}, {name: "with target and tombstone", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) - require.NoError(t, s.Put(&tomb, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) + require.NoError(t, s.Put(context.Background(), &tomb, nil)) }, assertPutErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "tombstone without target", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&tomb, nil)) + require.NoError(t, s.Put(context.Background(), &tomb, nil)) }, assertPutErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) }}, {name: "with target and GC mark", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) - err := s.Delete(objAddr) + err := s.Delete(context.Background(), objAddr) require.NoError(t, err) }}, } { @@ -206,9 +207,9 @@ func testPutLock(t *testing.T, shardNum int) { tc.preset(t, s) - putErr := s.Put(&lock, nil) - locked, lockedErr := s.IsLocked(objAddr) - got, getErr := s.Get(lockAddr) + putErr := s.Put(context.Background(), &lock, nil) + locked, lockedErr := s.IsLocked(context.Background(), objAddr) + got, getErr := s.Get(context.Background(), lockAddr) if tc.assertPutErr != nil { tc.assertPutErr(t, putErr) @@ -273,23 +274,23 @@ func testPutTombstone(t *testing.T, shardNum int) { }{ {name: "no target", preset: func(t *testing.T, s *StorageEngine) {}}, {name: "with target", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) }}, {name: "with target and lock", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&obj, nil)) - require.NoError(t, s.Put(&lock, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) + require.NoError(t, s.Put(context.Background(), &lock, nil)) }, assertPutErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectLocked) }}, {name: "lock without target", preset: func(t *testing.T, s *StorageEngine) { - require.NoError(t, s.Put(&lock, nil)) + require.NoError(t, s.Put(context.Background(), &lock, nil)) }, assertPutErr: func(t *testing.T, err error) { require.ErrorIs(t, err, apistatus.ErrObjectLocked) }}, {name: "target is lock", preset: func(t *testing.T, s *StorageEngine) { obj := obj obj.AssociateLocked(oidtest.ID()) - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) }, assertPutErr: func(t *testing.T, err error) { require.ErrorIs(t, err, meta.ErrLockObjectRemoval) }}, @@ -299,7 +300,7 @@ func testPutTombstone(t *testing.T, shardNum int) { object.NewAttribute("__NEOFS__EXPIRATION_EPOCH", strconv.Itoa(100)), ) obj.AssociateDeleted(oidtest.ID()) - require.NoError(t, s.Put(&obj, nil)) + require.NoError(t, s.Put(context.Background(), &obj, nil)) }, assertPutErr: func(t *testing.T, err error) { require.EqualError(t, err, "could not put object to any shard") }, skip: "https://github.com/nspcc-dev/neofs-node/issues/3498"}, @@ -313,9 +314,9 @@ func testPutTombstone(t *testing.T, shardNum int) { tc.preset(t, s) - putTombErr := s.Put(&tomb, nil) - gotTomb, getTombErr := s.Get(tombAddr) - _, getObjErr := s.Get(objAddr) + putTombErr := s.Put(context.Background(), &tomb, nil) + gotTomb, getTombErr := s.Get(context.Background(), tombAddr) + _, getObjErr := s.Get(context.Background(), objAddr) if tc.assertPutErr != nil { tc.assertPutErr(t, putTombErr) diff --git a/pkg/local_object_storage/engine/range.go b/pkg/local_object_storage/engine/range.go index 6725891279..ad50ccb06f 100644 --- a/pkg/local_object_storage/engine/range.go +++ b/pkg/local_object_storage/engine/range.go @@ -1,6 +1,7 @@ package engine import ( + "context" "errors" "io" @@ -21,12 +22,12 @@ import ( // // If referenced object is a parent of some stored EC parts, GetRange returns // [ierrors.ErrParentObject] wrapping [iec.ErrParts]. -func (e *StorageEngine) GetRange(addr oid.Address, offset uint64, length uint64) ([]byte, error) { +func (e *StorageEngine) GetRange(ctx context.Context, addr oid.Address, offset uint64, length uint64) ([]byte, error) { if e.metrics != nil { defer elapsed(e.metrics.AddRangeDuration)() } - stream, err := e.getRangeStream(addr, offset, length) + stream, err := e.getRangeStream(ctx, addr, offset, length) if err != nil { return nil, err } diff --git a/pkg/local_object_storage/engine/revive.go b/pkg/local_object_storage/engine/revive.go index 24adc20216..1fe072c09d 100644 --- a/pkg/local_object_storage/engine/revive.go +++ b/pkg/local_object_storage/engine/revive.go @@ -1,6 +1,8 @@ package engine import ( + "context" + meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" "go.uber.org/zap" @@ -19,7 +21,7 @@ type ReviveStatus struct { // ReviveObject forcefully revives object by oid.Address in the StorageEngine. // Iterate over all shards despite errors and purge all removal marks from all metabases. -func (e *StorageEngine) ReviveObject(address oid.Address) (ReviveStatus, error) { +func (e *StorageEngine) ReviveObject(_ context.Context, address oid.Address) (ReviveStatus, error) { var res ReviveStatus for _, sh := range e.unsortedShards() { diff --git a/pkg/local_object_storage/engine/revive_test.go b/pkg/local_object_storage/engine/revive_test.go index ac7a6fd21c..9c5ff77f25 100644 --- a/pkg/local_object_storage/engine/revive_test.go +++ b/pkg/local_object_storage/engine/revive_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "testing" meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase" @@ -17,7 +18,7 @@ func TestStorageEngine_ReviveObject(t *testing.T) { cnr := cidtest.ID() obj := generateObjectWithCID(cnr) - require.NoError(t, e.Put(obj, nil)) + require.NoError(t, e.Put(context.Background(), obj, nil)) addr := obj.Address() ts := generateObjectWithCID(cnr) @@ -25,21 +26,21 @@ func TestStorageEngine_ReviveObject(t *testing.T) { addAttribute(ts, object.AttributeExpirationEpoch, "0") tsAddr := ts.Address() - require.NoError(t, e.Put(ts, nil)) + require.NoError(t, e.Put(context.Background(), ts, nil)) - _, err := e.Get(addr) + _, err := e.Get(context.Background(), addr) require.ErrorIs(t, err, apistatus.ErrObjectAlreadyRemoved) - rs, err := e.ReviveObject(addr) + rs, err := e.ReviveObject(context.Background(), addr) require.NoError(t, err) require.Equal(t, meta.ReviveStatusGraveyard, rs.Shards[0].Status.StatusType()) require.Equal(t, tsAddr, rs.Shards[0].Status.TombstoneAddress()) - got, err := e.Get(addr) + got, err := e.Get(context.Background(), addr) require.NoError(t, err) require.Equal(t, obj, got) // tombstone metadata should be dropped, so getting TS must fail with not found - _, err = e.Get(tsAddr) + _, err = e.Get(context.Background(), tsAddr) require.ErrorIs(t, err, apistatus.ErrObjectNotFound) } diff --git a/pkg/local_object_storage/engine/select.go b/pkg/local_object_storage/engine/select.go index 25e910b9e7..cf3e516be5 100644 --- a/pkg/local_object_storage/engine/select.go +++ b/pkg/local_object_storage/engine/select.go @@ -2,6 +2,7 @@ package engine import ( "bytes" + "context" "errors" "fmt" @@ -17,7 +18,7 @@ import ( // Returns any error encountered that did not allow to completely select the objects. // // Returns an error if executions are blocked (see BlockExecution). -func (e *StorageEngine) selectOld(cnr cid.ID, filters object.SearchFilters) ([]oid.Address, error) { +func (e *StorageEngine) selectOld(_ context.Context, cnr cid.ID, filters object.SearchFilters) ([]oid.Address, error) { if e.metrics != nil { defer elapsed(e.metrics.AddSearchDuration)() } @@ -56,7 +57,7 @@ func (e *StorageEngine) selectOld(cnr cid.ID, filters object.SearchFilters) ([]o // Search performs Search op on all underlying shards and returns merged result. // // Fails instantly if executions are blocked (see [StorageEngine.BlockExecution]). -func (e *StorageEngine) Search(cnr cid.ID, fs []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]client.SearchResultItem, []byte, error) { +func (e *StorageEngine) Search(_ context.Context, cnr cid.ID, fs []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]client.SearchResultItem, []byte, error) { if e.metrics != nil { defer elapsed(e.metrics.AddSearchDuration)() } diff --git a/pkg/local_object_storage/engine/status.go b/pkg/local_object_storage/engine/status.go index 53889f56f1..296b8bb304 100644 --- a/pkg/local_object_storage/engine/status.go +++ b/pkg/local_object_storage/engine/status.go @@ -1,6 +1,8 @@ package engine import ( + "context" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" ) @@ -17,7 +19,7 @@ type ObjectStatus struct { } // ObjectStatus returns the status of the object in the StorageEngine. It contains status of the object in all shards. -func (e *StorageEngine) ObjectStatus(address oid.Address) (ObjectStatus, error) { +func (e *StorageEngine) ObjectStatus(_ context.Context, address oid.Address) (ObjectStatus, error) { var res ObjectStatus for _, sh := range e.sortedShards(address.Object()) { diff --git a/pkg/services/control/server/evacuate.go b/pkg/services/control/server/evacuate.go index 9b711442e2..383fab73ec 100644 --- a/pkg/services/control/server/evacuate.go +++ b/pkg/services/control/server/evacuate.go @@ -19,7 +19,7 @@ import ( "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) if err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) @@ -36,7 +36,7 @@ func (s *Server) EvacuateShard(_ context.Context, req *control.EvacuateShardRequ return nil, status.Error(codes.InvalidArgument, err.Error()) } - count, err := s.storage.Evacuate(shardIDs, req.GetBody().GetIgnoreErrors(), s.replicate) + count, err := s.storage.Evacuate(ctx, shardIDs, req.GetBody().GetIgnoreErrors(), s.replicate) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/pkg/services/control/server/gc.go b/pkg/services/control/server/gc.go index 67ff85f370..578ba91fce 100644 --- a/pkg/services/control/server/gc.go +++ b/pkg/services/control/server/gc.go @@ -16,7 +16,7 @@ import ( // // If some address is not a valid object address in a binary format, an error returns. // If request is unsigned or signed by disallowed key, permission error returns. -func (s *Server) DropObjects(_ context.Context, req *control.DropObjectsRequest) (*control.DropObjectsResponse, error) { +func (s *Server) DropObjects(ctx context.Context, req *control.DropObjectsRequest) (*control.DropObjectsResponse, error) { // verify request if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) @@ -42,7 +42,7 @@ func (s *Server) DropObjects(_ context.Context, req *control.DropObjectsRequest) var firstErr error for i := range addrList { - err := s.storage.Drop(addrList[i]) + err := s.storage.Drop(ctx, addrList[i]) if err != nil && firstErr == nil { firstErr = err } diff --git a/pkg/services/control/server/list_objects.go b/pkg/services/control/server/list_objects.go index d71e8159c3..bdcdc5d292 100644 --- a/pkg/services/control/server/list_objects.go +++ b/pkg/services/control/server/list_objects.go @@ -23,13 +23,14 @@ func (s *Server) ListObjects(req *control.ListObjectsRequest, stream control.Con } var ( + ctx = stream.Context() cursor *engine.Cursor addresses []objectcore.AddressWithAttributes ) // (Limit 4MB - 64KB for service bytes and future fields) / 89B address length = 46390 addresses can be sent const count = 46390 for { - addresses, cursor, err = s.storage.ListWithCursor(count, cursor) + addresses, cursor, err = s.storage.ListWithCursor(ctx, count, cursor) if err != nil { if errors.Is(err, engine.ErrEndOfListing) { return nil diff --git a/pkg/services/control/server/object_revive.go b/pkg/services/control/server/object_revive.go index 1a8f0454ec..757b5cd765 100644 --- a/pkg/services/control/server/object_revive.go +++ b/pkg/services/control/server/object_revive.go @@ -9,7 +9,7 @@ import ( "google.golang.org/grpc/status" ) -func (s *Server) ReviveObject(_ context.Context, request *control.ReviveObjectRequest) (*control.ReviveObjectResponse, error) { +func (s *Server) ReviveObject(ctx context.Context, request *control.ReviveObjectRequest) (*control.ReviveObjectResponse, error) { err := s.isValidRequest(request) if err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) @@ -27,7 +27,7 @@ func (s *Server) ReviveObject(_ context.Context, request *control.ReviveObjectRe return nil, status.Errorf(codes.InvalidArgument, "parsing object address: %s", err) } - res, err := s.storage.ReviveObject(addr) + res, err := s.storage.ReviveObject(ctx, addr) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/pkg/services/control/server/object_status.go b/pkg/services/control/server/object_status.go index 23f9638e22..8f37887225 100644 --- a/pkg/services/control/server/object_status.go +++ b/pkg/services/control/server/object_status.go @@ -11,7 +11,7 @@ import ( "google.golang.org/grpc/status" ) -func (s *Server) ObjectStatus(_ context.Context, request *control.ObjectStatusRequest) (*control.ObjectStatusResponse, error) { +func (s *Server) ObjectStatus(ctx context.Context, request *control.ObjectStatusRequest) (*control.ObjectStatusResponse, error) { err := s.isValidRequest(request) if err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) @@ -29,7 +29,7 @@ func (s *Server) ObjectStatus(_ context.Context, request *control.ObjectStatusRe return nil, status.Errorf(codes.InvalidArgument, "parsing object address: %s", err) } - st, err := s.storage.ObjectStatus(addr) + st, err := s.storage.ObjectStatus(ctx, addr) if err != nil { return nil, status.Errorf(codes.Internal, "storage engine error: %s", err) } diff --git a/pkg/services/object/acl/acl.go b/pkg/services/object/acl/acl.go index 49724ccf8b..c842780c38 100644 --- a/pkg/services/object/acl/acl.go +++ b/pkg/services/object/acl/acl.go @@ -1,6 +1,7 @@ package acl import ( + "context" "crypto/ecdsa" "crypto/elliptic" "errors" @@ -108,7 +109,7 @@ func (c *Checker) StickyBitCheck(info v2.RequestInfo, owner user.ID) bool { } // CheckEACL is a main check function for extended ACL. -func (c *Checker) CheckEACL(msg any, reqInfo v2.RequestInfo) error { +func (c *Checker) CheckEACL(ctx context.Context, msg any, reqInfo v2.RequestInfo) error { basicACL := reqInfo.Container.BasicACL() if !basicACL.Extendable() { return nil @@ -156,6 +157,7 @@ func (c *Checker) CheckEACL(msg any, reqInfo v2.RequestInfo) error { hdrSrcOpts := make([]eaclV2.Option, 0, 3) hdrSrcOpts = append(hdrSrcOpts, + eaclV2.WithContext(ctx), eaclV2.WithLocalObjectStorage(c.localStorage), eaclV2.WithCID(cnr), eaclV2.WithOID(reqInfo.Obj), diff --git a/pkg/services/object/acl/acl_test.go b/pkg/services/object/acl/acl_test.go index 72bd22215e..5db18162bc 100644 --- a/pkg/services/object/acl/acl_test.go +++ b/pkg/services/object/acl/acl_test.go @@ -1,6 +1,7 @@ package acl import ( + "context" "testing" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" @@ -23,7 +24,7 @@ func (e emptyEACLSource) GetEACL(_ cid.ID) (eaclSDK.Table, error) { type emptyHeaderSource struct{} -func (e emptyHeaderSource) Head(address oid.Address) (*object.Object, error) { +func (e emptyHeaderSource) Head(_ context.Context, _ oid.Address) (*object.Object, error) { return nil, nil } diff --git a/pkg/services/object/acl/eacl/v2/eacl_test.go b/pkg/services/object/acl/eacl/v2/eacl_test.go index 6786b8583b..0ba4bbd4b6 100644 --- a/pkg/services/object/acl/eacl/v2/eacl_test.go +++ b/pkg/services/object/acl/eacl/v2/eacl_test.go @@ -1,6 +1,7 @@ package v2 import ( + "context" "crypto/ecdsa" "crypto/sha256" "errors" @@ -39,11 +40,11 @@ type testHeaderSource struct { header *object.Object } -func (t *testHeaderSource) Head(_ oid.Address) (*object.Object, error) { +func (t *testHeaderSource) Head(_ context.Context, _ oid.Address) (*object.Object, error) { return t.header, nil } -func (s *testLocalStorage) Head(addr oid.Address) (*object.Object, error) { +func (s *testLocalStorage) Head(_ context.Context, addr oid.Address) (*object.Object, error) { require.True(s.t, addr.Container() == s.expAddr.Container()) require.True(s.t, addr.Object() == s.expAddr.Object()) diff --git a/pkg/services/object/acl/eacl/v2/headers.go b/pkg/services/object/acl/eacl/v2/headers.go index cd49c288d5..43194438c0 100644 --- a/pkg/services/object/acl/eacl/v2/headers.go +++ b/pkg/services/object/acl/eacl/v2/headers.go @@ -1,6 +1,7 @@ package v2 import ( + "context" "errors" "fmt" @@ -18,6 +19,7 @@ type Option func(*cfg) type binaryHeader []byte type cfg struct { + ctx context.Context storage ObjectStorage headerSource HeaderSource @@ -28,13 +30,13 @@ type cfg struct { } type ObjectStorage interface { - Head(oid.Address) (*object.Object, error) + Head(ctx context.Context, addr oid.Address) (*object.Object, error) } // HeaderSource represents a source of the object headers. type HeaderSource interface { // Head returns object (may be with or be without payload) by its address. - Head(oid.Address) (*object.Object, error) + Head(ctx context.Context, addr oid.Address) (*object.Object, error) } type Request interface { @@ -55,6 +57,7 @@ type headerSource struct { func defaultCfg() *cfg { return &cfg{ + ctx: context.Background(), storage: new(localStorage), } } @@ -202,7 +205,7 @@ func (h *cfg) readObjectHeaders(dst *headerSource) error { addr.SetObject(firstID) addr.SetContainer(h.cnr) - firstObject, err := h.headerSource.Head(addr) + firstObject, err := h.headerSource.Head(h.ctx, addr) if err != nil { return fmt.Errorf("fetching first object header: %w", err) } @@ -297,7 +300,7 @@ func (h *cfg) localObjectHeaders(cnr cid.ID, idObj *oid.ID) ([]eaclSDK.Header, b addr.SetContainer(cnr) addr.SetObject(*idObj) - obj, err := h.storage.Head(addr) + obj, err := h.storage.Head(h.ctx, addr) if err == nil { return headersFromObject(obj, cnr, idObj), true } diff --git a/pkg/services/object/acl/eacl/v2/localstore.go b/pkg/services/object/acl/eacl/v2/localstore.go index a28b167211..5d44e3395f 100644 --- a/pkg/services/object/acl/eacl/v2/localstore.go +++ b/pkg/services/object/acl/eacl/v2/localstore.go @@ -1,6 +1,7 @@ package v2 import ( + "context" "io" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" @@ -12,10 +13,10 @@ type localStorage struct { ls *engine.StorageEngine } -func (s *localStorage) Head(addr oid.Address) (*object.Object, error) { +func (s *localStorage) Head(ctx context.Context, addr oid.Address) (*object.Object, error) { if s.ls == nil { return nil, io.ErrUnexpectedEOF } - return s.ls.Head(addr, false) + return s.ls.Head(ctx, addr, false) } diff --git a/pkg/services/object/acl/eacl/v2/opts.go b/pkg/services/object/acl/eacl/v2/opts.go index af53c243ac..6e05558b49 100644 --- a/pkg/services/object/acl/eacl/v2/opts.go +++ b/pkg/services/object/acl/eacl/v2/opts.go @@ -1,11 +1,19 @@ package v2 import ( + "context" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" ) +func WithContext(ctx context.Context) Option { + return func(c *cfg) { + c.ctx = ctx + } +} + func WithObjectStorage(v ObjectStorage) Option { return func(c *cfg) { c.storage = v diff --git a/pkg/services/object/acl/v2/types.go b/pkg/services/object/acl/v2/types.go index 90be5e6ab9..03adf10e8c 100644 --- a/pkg/services/object/acl/v2/types.go +++ b/pkg/services/object/acl/v2/types.go @@ -1,6 +1,8 @@ package v2 import ( + "context" + "github.com/nspcc-dev/neofs-sdk-go/user" ) @@ -12,7 +14,7 @@ type ACLChecker interface { CheckBasicACL(RequestInfo) bool // CheckEACL must return non-nil error if request // doesn't pass extended ACL validation. - CheckEACL(any, RequestInfo) error + CheckEACL(context.Context, any, RequestInfo) error // StickyBitCheck must return true only if sticky bit // is disabled or enabled but request contains correct // owner field. diff --git a/pkg/services/object/get.go b/pkg/services/object/get.go index eb6a174f7f..472001b810 100644 --- a/pkg/services/object/get.go +++ b/pkg/services/object/get.go @@ -56,7 +56,7 @@ func (x *getProxyContext) continueWithConn(ctx context.Context, conn *grpc.Clien return fmt.Errorf("reading the response failed: %w", err) } - fin, sent, err := x.handleGetResponse(&prog, respBuf) + fin, sent, err := x.handleGetResponse(ctx, &prog, respBuf) if !sent { respBuf.Free() } @@ -84,7 +84,7 @@ func (x *getProxyContext) validateEOF(prog getStreamProgress) error { return nil } -func (x *getProxyContext) handleGetResponse(streamProg *getStreamProgress, respBuf mem.BufferSlice) (bool, bool, error) { +func (x *getProxyContext) handleGetResponse(ctx context.Context, streamProg *getStreamProgress, respBuf mem.BufferSlice) (bool, bool, error) { var code uint32 var body iprotobuf.BuffersSlice @@ -121,7 +121,7 @@ func (x *getProxyContext) handleGetResponse(streamProg *getStreamProgress, respB // TODO: forbid body if code != OK? - sent, err := x.handleResponseBody(streamProg, respBuf, body) + sent, err := x.handleResponseBody(ctx, streamProg, respBuf, body) if err != nil { return false, sent, fmt.Errorf("handle body: %w", err) } @@ -129,7 +129,7 @@ func (x *getProxyContext) handleGetResponse(streamProg *getStreamProgress, respB return false, sent, nil } -func (x *getProxyContext) handleResponseBody(streamProg *getStreamProgress, respBuf mem.BufferSlice, buffers iprotobuf.BuffersSlice) (bool, error) { +func (x *getProxyContext) handleResponseBody(ctx context.Context, streamProg *getStreamProgress, respBuf mem.BufferSlice, buffers iprotobuf.BuffersSlice) (bool, error) { var oneofNum protowire.Number var oneofFld iprotobuf.BuffersSlice @@ -170,7 +170,7 @@ func (x *getProxyContext) handleResponseBody(streamProg *getStreamProgress, resp default: return false, errors.New("none of the supported oneof fields are specified") case protoobject.FieldGetResponseBodyInit: - return x.handleInitResponse(respBuf, oneofFld) + return x.handleInitResponse(ctx, respBuf, oneofFld) case protoobject.FieldGetResponseBodyChunk: return x.handleChunkResponse(streamProg, respBuf, oneofFld) case protoobject.FieldGetResponseBodySplitInfo: @@ -178,7 +178,7 @@ func (x *getProxyContext) handleResponseBody(streamProg *getStreamProgress, resp } } -func (x *getProxyContext) handleInitResponse(respBuf mem.BufferSlice, buffers iprotobuf.BuffersSlice) (bool, error) { +func (x *getProxyContext) handleInitResponse(ctx context.Context, respBuf mem.BufferSlice, buffers iprotobuf.BuffersSlice) (bool, error) { var hdr iprotobuf.BuffersSlice var opts protoscan.ScanMessageOptions @@ -229,7 +229,7 @@ func (x *getProxyContext) handleInitResponse(respBuf mem.BufferSlice, buffers ip var sent bool x.onceHdr.Do(func() { if x.respStream.recheckEACL { - err = x.respStream.srv.aclChecker.CheckEACL(hdr.ReadOnlyData(), x.respStream.reqInfo) + err = x.respStream.srv.aclChecker.CheckEACL(ctx, hdr.ReadOnlyData(), x.respStream.reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(x.respStream.reqInfo, err) return diff --git a/pkg/services/object/get/ec.go b/pkg/services/object/get/ec.go index 02e6d4b96f..7de2c285c4 100644 --- a/pkg/services/object/get/ec.go +++ b/pkg/services/object/get/ec.go @@ -38,8 +38,8 @@ func (x tooManyPartsUnavailableError) Error() string { // // Returns [apistatus.ErrObjectAlreadyRemoved] if the object was marked for // removal. Returns [apistatus.ErrObjectNotFound] if the object is missing. -func (s *Service) copyLocalECPart(dst ObjectWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo) error { - hdr, rc, err := s.localObjects.GetECPart(cnr, parent, pi) +func (s *Service) copyLocalECPart(ctx context.Context, dst ObjectWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo) error { + hdr, rc, err := s.localObjects.GetECPart(ctx, cnr, parent, pi) if err != nil { return fmt.Errorf("get object from local storage: %w", err) } @@ -53,8 +53,8 @@ func (s *Service) copyLocalECPart(dst ObjectWriter, cnr cid.ID, parent oid.ID, p } // similar to copyLocalECPart but returns only the header. -func (s *Service) copyLocalECPartHeader(dst internal.HeaderWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo) error { - hdr, err := s.localObjects.HeadECPart(cnr, parent, pi) +func (s *Service) copyLocalECPartHeader(ctx context.Context, dst internal.HeaderWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo) error { + hdr, err := s.localObjects.HeadECPart(ctx, cnr, parent, pi) if err != nil { return fmt.Errorf("get object header from local storage: %w", err) } @@ -121,14 +121,14 @@ func (s *Service) getECObjectHeaderByRule(ctx context.Context, localNodeKey ecds var err error if buf != nil { var n int - n, err = s.localObjects.ReadHeader(oid.NewAddress(cnr, id), false, buf) + n, err = s.localObjects.ReadHeader(ctx, oid.NewAddress(cnr, id), false, buf) if err == nil { submitLenFn(n) return object.Object{}, nil } } else { var hdr *object.Object - hdr, err = s.localStorage.(*storageEngineWrapper).engine.Head(oid.NewAddress(cnr, id), false) + hdr, err = s.localStorage.(*storageEngineWrapper).engine.Head(ctx, oid.NewAddress(cnr, id), false) if err == nil { return *hdr, nil } @@ -493,7 +493,7 @@ func (s *Service) getECPartStream(ctx context.Context, cnr cid.ID, parent oid.ID } if local { - partHdr, rc, err = s.localObjects.GetECPart(cnr, parent, pi) + partHdr, rc, err = s.localObjects.GetECPart(ctx, cnr, parent, pi) } else { partHdr, rc, err = s.getECPartFromNode(ctx, cnr, parent, sTok, pi, sortedNodes[i]) } @@ -656,8 +656,8 @@ func (s *Service) getECPartFromNode(ctx context.Context, cnr cid.ID, parent oid. // Returns [apistatus.ErrObjectAlreadyRemoved] if the object was marked for // removal. Returns [apistatus.ErrObjectNotFound] if the object is missing. // Returns [apistatus.ErrObjectOutOfRange] if the range is out of payload range. -func (s *Service) copyLocalECPartRange(dst ChunkWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) error { - pldLen, rc, err := s.localObjects.GetECPartRange(cnr, parent, pi, off, ln) +func (s *Service) copyLocalECPartRange(ctx context.Context, dst ChunkWriter, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) error { + pldLen, rc, err := s.localObjects.GetECPartRange(ctx, cnr, parent, pi, off, ln) if err != nil { return fmt.Errorf("get object payload range from local storage: %w", err) } @@ -1236,7 +1236,7 @@ func (s *Service) getECPartRangeStream(ctx context.Context, cnr cid.ID, parent o } if local { - _, rc, err = s.localObjects.GetECPartRange(cnr, parent, pi, off, ln) + _, rc, err = s.localObjects.GetECPartRange(ctx, cnr, parent, pi, off, ln) if err == nil || errors.Is(err, apistatus.ErrObjectAlreadyRemoved) || errors.Is(err, apistatus.ErrObjectOutOfRange) { return rc, err } diff --git a/pkg/services/object/get/get.go b/pkg/services/object/get/get.go index e675e1b0e1..06114a70c1 100644 --- a/pkg/services/object/get/get.go +++ b/pkg/services/object/get/get.go @@ -25,24 +25,24 @@ func (s *Service) Get(ctx context.Context, prm Prm) error { if prm.rng != nil { if prm.payloadOnly && prm.localGetBuffer != nil { - stream, err := s.localObjects.ReadECPartRange(prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength(), prm.localGetBuffer) + stream, err := s.localObjects.ReadECPartRange(ctx, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength(), prm.localGetBuffer) if err == nil { prm.submitLocalGetStreamFn(0, stream) } return err } - return s.copyLocalECPartRange(prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength()) + return s.copyLocalECPartRange(ctx, prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength()) } if prm.localGetBuffer != nil { - n, stream, err := s.localObjects.ReadECPart(prm.addr.Container(), prm.addr.Object(), pi, prm.localGetBuffer) + n, stream, err := s.localObjects.ReadECPart(ctx, prm.addr.Container(), prm.addr.Object(), pi, prm.localGetBuffer) if err == nil { prm.submitLocalGetStreamFn(n, stream) } return err } - return s.copyLocalECPart(prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi) + return s.copyLocalECPart(ctx, prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi) } if prm.common.LocalOnly() && @@ -127,14 +127,14 @@ func (s *Service) GetRange(ctx context.Context, prm RangePrm) error { // TODO: deny if node is not in the container? if prm.localBuffer != nil { - stream, err := s.localObjects.ReadECPartRange(prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength(), prm.localBuffer) + stream, err := s.localObjects.ReadECPartRange(ctx, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength(), prm.localBuffer) if err == nil { prm.submitLocalStreamFn(stream) } return err } - return s.copyLocalECPartRange(prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength()) + return s.copyLocalECPartRange(ctx, prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi, prm.rng.GetOffset(), prm.rng.GetLength()) } if prm.common.LocalOnly() && @@ -216,26 +216,26 @@ func (s *Service) Head(ctx context.Context, prm HeadPrm) error { // TODO: deny if node is not in the container? if prm.buffer != nil { - n, err := s.localObjects.ReadECPartHeader(prm.addr.Container(), prm.addr.Object(), pi, prm.buffer) + n, err := s.localObjects.ReadECPartHeader(ctx, prm.addr.Container(), prm.addr.Object(), pi, prm.buffer) if err == nil { prm.submitLenFn(n) } return err } - return s.copyLocalECPartHeader(prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi) + return s.copyLocalECPartHeader(ctx, prm.objWriter, prm.addr.Container(), prm.addr.Object(), pi) } if prm.common.LocalOnly() { if prm.buffer != nil { - n, err := s.localObjects.ReadHeader(prm.addr, prm.raw, prm.buffer) + n, err := s.localObjects.ReadHeader(ctx, prm.addr, prm.raw, prm.buffer) if err == nil { prm.submitLenFn(n) } return err } - return s.copyLocalObjectHeader(prm.objWriter, prm.addr.Container(), prm.addr.Object(), prm.raw) + return s.copyLocalObjectHeader(ctx, prm.objWriter, prm.addr.Container(), prm.addr.Object(), prm.raw) } nodeLists, repRules, ecRules, err := s.neoFSNet.GetNodesForObject(prm.addr) diff --git a/pkg/services/object/get/get_test.go b/pkg/services/object/get/get_test.go index b73cc127f3..8cb89f7dd6 100644 --- a/pkg/services/object/get/get_test.go +++ b/pkg/services/object/get/get_test.go @@ -159,7 +159,7 @@ func (s *testStorage) get(exec *execCtx) (*object.Object, io.ReadCloser, error) return nil, nil, errNotFound } -func (s *testStorage) Head(addr oid.Address, _ bool) (*object.Object, error) { +func (s *testStorage) Head(_ context.Context, addr oid.Address, _ bool) (*object.Object, error) { hdr, _, err := s.get(&execCtx{ prm: RangePrm{ commonPrm: commonPrm{ @@ -1457,7 +1457,7 @@ func (s *testStorageWithFailingReader) get(*execCtx) (*object.Object, io.ReadClo return objWithoutPayload, reader, nil } -func (s *testStorageWithFailingReader) Head(oid.Address, bool) (*object.Object, error) { +func (s *testStorageWithFailingReader) Head(_ context.Context, _ oid.Address, _ bool) (*object.Object, error) { if s.obj == nil { return nil, errors.New("object not found") } @@ -1480,7 +1480,7 @@ func (s *testStorageWithImmediateReadError) get(*execCtx) (*object.Object, io.Re return objWithoutPayload, &errorReader{err: s.err}, nil } -func (s *testStorageWithImmediateReadError) Head(oid.Address, bool) (*object.Object, error) { +func (s *testStorageWithImmediateReadError) Head(_ context.Context, _ oid.Address, _ bool) (*object.Object, error) { if s.obj == nil { return nil, errors.New("object not found") } diff --git a/pkg/services/object/get/local.go b/pkg/services/object/get/local.go index 9d8831df64..401e757414 100644 --- a/pkg/services/object/get/local.go +++ b/pkg/services/object/get/local.go @@ -1,6 +1,7 @@ package getsvc import ( + "context" "errors" "fmt" @@ -51,8 +52,8 @@ func (exec *execCtx) executeLocal() { } } -func (s *Service) copyLocalObjectHeader(dst internal.HeaderWriter, cnr cid.ID, id oid.ID, raw bool) error { - hdr, err := s.localObjects.Head(oid.NewAddress(cnr, id), raw) +func (s *Service) copyLocalObjectHeader(ctx context.Context, dst internal.HeaderWriter, cnr cid.ID, id oid.ID, raw bool) error { + hdr, err := s.localObjects.Head(ctx, oid.NewAddress(cnr, id), raw) if err != nil { return fmt.Errorf("get object header from local storage: %w", err) } diff --git a/pkg/services/object/get/service.go b/pkg/services/object/get/service.go index aa496d6f0c..953a9117e4 100644 --- a/pkg/services/object/get/service.go +++ b/pkg/services/object/get/service.go @@ -73,25 +73,25 @@ type cfg struct { // // Returns [apistatus.ErrObjectAlreadyRemoved] if the object was marked for // removal. Returns [apistatus.ErrObjectNotFound] if the object is missing. - GetECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) + GetECPart(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) // GetECPartRange reads specified payload ranage of stored object that carries // EC part produced within cnr for parent object and indexed by pi. // // Returns [apistatus.ErrObjectAlreadyRemoved] if the object was marked for // removal. Returns [apistatus.ErrObjectNotFound] if the object is missing. // Returns [apistatus.ErrObjectNotFound] if the range is out of payload bounds. - GetECPartRange(cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) (uint64, io.ReadCloser, error) + GetECPartRange(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64) (uint64, io.ReadCloser, error) // ReadECPart is a buffered alternative for GetECPart similar to ReadObject. - ReadECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, io.ReadCloser, error) + ReadECPart(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, io.ReadCloser, error) // ReadECPartRange is a buffered alternative for GetECPartRange similar to ReadECPart. - ReadECPartRange(cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64, buf []byte) (io.ReadCloser, error) - Head(oid.Address, bool) (*object.Object, error) - ReadHeader(oid.Address, bool, []byte) (int, error) + ReadECPartRange(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, off, ln uint64, buf []byte) (io.ReadCloser, error) + Head(context.Context, oid.Address, bool) (*object.Object, error) + ReadHeader(context.Context, oid.Address, bool, []byte) (int, error) // HeadECPart is similar to GetECPart but returns only the header. - HeadECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, error) + HeadECPart(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, error) // ReadECPartHeader is a buffered alternative for HeadECPart similar to // ReadHeader. - ReadECPartHeader(cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, error) + ReadECPartHeader(ctx context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo, buf []byte) (int, error) } localStorage interface { get(*execCtx) (*object.Object, io.ReadCloser, error) diff --git a/pkg/services/object/get/service_test.go b/pkg/services/object/get/service_test.go index 61c7cbe448..02f95a5785 100644 --- a/pkg/services/object/get/service_test.go +++ b/pkg/services/object/get/service_test.go @@ -133,7 +133,7 @@ type mockLocalObjects struct { getECPart map[getECPartKey]getECPartValue } -func (x *mockLocalObjects) GetECPart(cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) { +func (x *mockLocalObjects) GetECPart(_ context.Context, cnr cid.ID, parent oid.ID, pi iec.PartInfo) (object.Object, io.ReadCloser, error) { v, ok := x.getECPart[getECPartKey{ cnr: cnr, parent: parent, @@ -190,34 +190,34 @@ func (x unimplementedServiceConns) Head(context.Context, netmap.NodeInfo, ecdsa. type unimplementedLocalStorage struct{} -func (x unimplementedLocalStorage) GetECPartRange(cid.ID, oid.ID, iec.PartInfo, uint64, uint64) (uint64, io.ReadCloser, error) { +func (x unimplementedLocalStorage) GetECPartRange(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo, _, _ uint64) (uint64, io.ReadCloser, error) { panic("unimplemented") } -func (unimplementedLocalStorage) GetECPart(cid.ID, oid.ID, iec.PartInfo) (object.Object, io.ReadCloser, error) { +func (unimplementedLocalStorage) GetECPart(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo) (object.Object, io.ReadCloser, error) { panic("unimplemented") } -func (unimplementedLocalStorage) ReadECPart(cid.ID, oid.ID, iec.PartInfo, []byte) (int, io.ReadCloser, error) { +func (unimplementedLocalStorage) ReadECPart(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo, _ []byte) (int, io.ReadCloser, error) { panic("unimplemented") } -func (unimplementedLocalStorage) Head(oid.Address, bool) (*object.Object, error) { +func (unimplementedLocalStorage) Head(_ context.Context, _ oid.Address, _ bool) (*object.Object, error) { panic("unimplemented") } -func (unimplementedLocalStorage) ReadHeader(oid.Address, bool, []byte) (int, error) { +func (unimplementedLocalStorage) ReadHeader(_ context.Context, _ oid.Address, _ bool, _ []byte) (int, error) { panic("unimplemented") } -func (unimplementedLocalStorage) HeadECPart(cid.ID, oid.ID, iec.PartInfo) (object.Object, error) { +func (unimplementedLocalStorage) HeadECPart(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo) (object.Object, error) { panic("unimplemented") } -func (unimplementedLocalStorage) ReadECPartHeader(cid.ID, oid.ID, iec.PartInfo, []byte) (int, error) { +func (unimplementedLocalStorage) ReadECPartHeader(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo, _ []byte) (int, error) { panic("unimplemented") } -func (unimplementedLocalStorage) ReadECPartRange(cid.ID, oid.ID, iec.PartInfo, uint64, uint64, []byte) (io.ReadCloser, error) { +func (unimplementedLocalStorage) ReadECPartRange(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo, _, _ uint64, _ []byte) (io.ReadCloser, error) { panic("unimplemented") } diff --git a/pkg/services/object/get/util.go b/pkg/services/object/get/util.go index 398fcd5060..5f72a59949 100644 --- a/pkg/services/object/get/util.go +++ b/pkg/services/object/get/util.go @@ -385,8 +385,9 @@ func (c *clientWrapper) get(exec *execCtx, key *ecdsa.PrivateKey) (*object.Objec } func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, io.ReadCloser, error) { + ctx := exec.context() if exec.headOnly() { - r, err := e.engine.Head(exec.address(), exec.isRaw()) + r, err := e.engine.Head(ctx, exec.address(), exec.isRaw()) if err != nil { return nil, nil, err } @@ -396,18 +397,18 @@ func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, io.ReadCloser if rng := exec.ctxRange(); rng != nil { if exec.localRangeBuffer != nil { - r, err := e.engine.ReadPayloadRange(exec.address(), rng.GetOffset(), rng.GetLength(), exec.localRangeBuffer) + r, err := e.engine.ReadPayloadRange(ctx, exec.address(), rng.GetOffset(), rng.GetLength(), exec.localRangeBuffer) if err == nil { exec.submitLocalRangeStreamFn(r) } return nil, nil, err } - r, err := e.engine.GetRangeStream(exec.address(), rng.GetOffset(), rng.GetLength()) + r, err := e.engine.GetRangeStream(ctx, exec.address(), rng.GetOffset(), rng.GetLength()) if err != nil { return nil, r, err } // TODO: avoid extra local HEAD once we can get header with range stream from engine in one call. - h, hErr := e.engine.Head(exec.address(), exec.isRaw()) + h, hErr := e.engine.Head(ctx, exec.address(), exec.isRaw()) if hErr != nil { if r != nil { _ = r.Close() @@ -418,14 +419,14 @@ func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, io.ReadCloser } if exec.localGetBuffer != nil { - n, stream, err := e.engine.ReadObject(exec.address(), exec.localGetBuffer) + n, stream, err := e.engine.ReadObject(ctx, exec.address(), exec.localGetBuffer) if err == nil { exec.submitLocalGetStreamFn(n, stream) } return nil, nil, err } - return e.engine.GetStream(exec.address()) + return e.engine.GetStream(ctx, exec.address()) } func (w *partWriter) WriteChunk(p []byte) error { diff --git a/pkg/services/object/get_test.go b/pkg/services/object/get_test.go index 3aabc8a9ed..8e926885d3 100644 --- a/pkg/services/object/get_test.go +++ b/pkg/services/object/get_test.go @@ -68,7 +68,7 @@ func TestServer_Get_Local(t *testing.T) { obj.SetPayload(testutil.RandByteSlice(pldLen)) require.NoError(t, obj.SetVerificationFields(signer)) - require.NoError(t, storage.Put(obj, nil)) + require.NoError(t, storage.Put(context.Background(), obj, nil)) assertGetOK(t, srv, mtrc, *obj, signer) @@ -118,7 +118,7 @@ func TestServer_Get_Local(t *testing.T) { }) // any part payload require.NoError(t, err) - require.NoError(t, storage.Put(&part, nil)) + require.NoError(t, storage.Put(context.Background(), &part, nil)) req := newUnsignedLocalGetRequest(version.Current(), parentHdr.Address()) req.MetaHeader.XHeaders = []*protosession.XHeader{ @@ -153,7 +153,7 @@ func TestServer_Get_Remote(t *testing.T) { storage := newSimpleStorage(t, fsChain) - require.NoError(t, storage.Put(obj, nil)) + require.NoError(t, storage.Put(context.Background(), obj, nil)) keyStorage := util.NewKeyStorage(&signer.ECDSAPrivateKey, nil, nil) diff --git a/pkg/services/object/head_test.go b/pkg/services/object/head_test.go index 615def197d..4e8221f6ba 100644 --- a/pkg/services/object/head_test.go +++ b/pkg/services/object/head_test.go @@ -47,7 +47,7 @@ func TestServer_Head_Local(t *testing.T) { storage := newSimpleStorage(t, fsChain) - require.NoError(t, storage.Put(obj, nil)) + require.NoError(t, storage.Put(context.Background(), obj, nil)) var handlerFSChain mockHandlerFSChain @@ -77,7 +77,7 @@ func TestServer_Head_Local(t *testing.T) { }) // payload is not needed require.NoError(t, err) - require.NoError(t, storage.Put(&partHdr, nil)) + require.NoError(t, storage.Put(context.Background(), &partHdr, nil)) req := newUnsignedLocalHeadRequest(version.Current(), obj.Address()) req.MetaHeader.XHeaders = []*protosession.XHeader{ @@ -122,7 +122,7 @@ func TestServer_Head_Remote(t *testing.T) { storage := newSimpleStorage(t, fsChain) - require.NoError(t, storage.Put(obj, nil)) + require.NoError(t, storage.Put(context.Background(), obj, nil)) keyStorage := util.NewKeyStorage(&signer.ECDSAPrivateKey, nil, nil) @@ -157,7 +157,7 @@ func TestServer_Head_Remote(t *testing.T) { }) // any part payload require.NoError(t, err) - require.NoError(t, storage.Put(&partHdr, nil)) + require.NoError(t, storage.Put(context.Background(), &partHdr, nil)) req := newUnsignedLocalHeadRequest(version.Current(), obj.Address()) req.MetaHeader.Ttl = 2 diff --git a/pkg/services/object/put/distributed.go b/pkg/services/object/put/distributed.go index 8ddb99b711..ae6f4a4fc0 100644 --- a/pkg/services/object/put/distributed.go +++ b/pkg/services/object/put/distributed.go @@ -161,7 +161,7 @@ func (t *distributedTarget) Close() (oid.ID, error) { // does not matter what this node thinks about it if !tombOrLink || t.localNodeInContainer { var err error - if err = t.fmt.ValidateContent(t.obj); err != nil { + if err = t.fmt.ValidateContent(t.opCtx, t.obj); err != nil { return oid.ID{}, fmt.Errorf("(%T) could not validate payload content: %w", t, err) } } @@ -707,7 +707,7 @@ func (t *distributedTarget) sendObject(obj object.Object, encObj encodedObject, } func (t *distributedTarget) writeObjectLocally(obj object.Object, encObj encodedObject) error { - if err := putObjectLocally(t.localStorage, &obj, &encObj); err != nil { + if err := putObjectLocally(t.opCtx, t.localStorage, &obj, &encObj); err != nil { return err } diff --git a/pkg/services/object/put/local.go b/pkg/services/object/put/local.go index 2a8ca09288..bd50612634 100644 --- a/pkg/services/object/put/local.go +++ b/pkg/services/object/put/local.go @@ -2,6 +2,7 @@ package putsvc import ( "bytes" + "context" "crypto/sha256" "errors" "fmt" @@ -18,18 +19,18 @@ type ObjectStorage interface { // // Optional objBin parameter carries object encoded in a canonical NeoFS binary // format. - Put(obj *object.Object, objBin []byte) error + Put(ctx context.Context, obj *object.Object, objBin []byte) error // IsLocked must clarify object's lock status. - IsLocked(oid.Address) (bool, error) + IsLocked(ctx context.Context, addr oid.Address) (bool, error) } -func putObjectLocally(storage ObjectStorage, obj *object.Object, enc *encodedObject) error { +func putObjectLocally(ctx context.Context, storage ObjectStorage, obj *object.Object, enc *encodedObject) error { var objBin []byte if enc != nil && enc.pldOff > 0 { objBin = enc.b[enc.hdrOff:] } - if err := storage.Put(obj, objBin); err != nil { + if err := storage.Put(ctx, obj, objBin); err != nil { return fmt.Errorf("could not put object to local storage: %w", err) } @@ -39,7 +40,7 @@ func putObjectLocally(storage ObjectStorage, obj *object.Object, enc *encodedObj // ValidateAndStoreObjectLocally checks format of given object and, if it's // correct, stores it in the underlying local object storage. Serves operation // similar to local-only [Service.Put] one. -func (p *Service) ValidateAndStoreObjectLocally(obj object.Object) error { +func (p *Service) ValidateAndStoreObjectLocally(ctx context.Context, obj object.Object) error { cnrID := obj.GetContainerID() if cnrID.IsZero() { return errors.New("missing container ID") @@ -75,11 +76,11 @@ func (p *Service) ValidateAndStoreObjectLocally(obj object.Object) error { return ErrExceedingMaxSize } - if err := p.fmtValidator.Validate(&obj, false, true); err != nil { + if err := p.fmtValidator.Validate(ctx, &obj, false, true); err != nil { return fmt.Errorf("validate object format: %w", err) } - err := p.fmtValidator.ValidateContent(&obj) + err := p.fmtValidator.ValidateContent(ctx, &obj) if err != nil { return fmt.Errorf("validate payload content: %w", err) } @@ -90,5 +91,5 @@ func (p *Service) ValidateAndStoreObjectLocally(obj object.Object) error { return errors.New("payload SHA-256 checksum mismatch") } - return putObjectLocally(p.localStore, &obj, nil) + return putObjectLocally(ctx, p.localStore, &obj, nil) } diff --git a/pkg/services/object/put/service_test.go b/pkg/services/object/put/service_test.go index 708a53feda..549cd91b97 100644 --- a/pkg/services/object/put/service_test.go +++ b/pkg/services/object/put/service_test.go @@ -942,7 +942,7 @@ func (x testPostPlacementReplicator) HandlePostPlacement(obj *object.Object, nod for i := range nodes { svc, err := x.services.lookupNode(nodes[i]) require.NoError(x.t, err) - require.NoError(x.t, svc.ValidateAndStoreObjectLocally(*obj)) //nolint:contextcheck + require.NoError(x.t, svc.ValidateAndStoreObjectLocally(context.Background(), *obj)) } } @@ -952,7 +952,7 @@ type inMemLocalStorage struct { err error } -func (x *inMemLocalStorage) Put(obj *object.Object, objBin []byte) error { +func (x *inMemLocalStorage) Put(_ context.Context, obj *object.Object, objBin []byte) error { if x.err != nil { return x.err } @@ -991,7 +991,7 @@ func (x *inMemLocalStorage) Lock(oid.Address, []oid.ID) error { panic("unimplemented") } -func (x *inMemLocalStorage) IsLocked(oid.Address) (bool, error) { +func (x *inMemLocalStorage) IsLocked(context.Context, oid.Address) (bool, error) { panic("unimplemented") } @@ -1015,7 +1015,7 @@ func (x nodeServices) Get(_ context.Context, node netmap.NodeInfo) (clientcore.M return (*serviceClient)(svc), nil } -func (x nodeServices) SendReplicationRequestToNode(_ context.Context, reqBin []byte, node netmap.NodeInfo) ([]byte, error) { +func (x nodeServices) SendReplicationRequestToNode(ctx context.Context, reqBin []byte, node netmap.NodeInfo) ([]byte, error) { var req protoobject.ReplicateRequest if err := proto.Unmarshal(reqBin, &req); err != nil { return nil, fmt.Errorf("invalid request: %w", err) @@ -1035,7 +1035,7 @@ func (x nodeServices) SendReplicationRequestToNode(_ context.Context, reqBin []b return nil, err } - if err := svc.ValidateAndStoreObjectLocally(obj); err != nil { //nolint:contextcheck + if err := svc.ValidateAndStoreObjectLocally(ctx, obj); err != nil { return nil, fmt.Errorf("validate and store object locally: %w", err) } @@ -1070,7 +1070,7 @@ func (m *serviceClient) ObjectPutInit(ctx context.Context, hdr object.Object, _ return (*testPayloadStream)(stream), nil } -func (m *serviceClient) ReplicateObject(_ context.Context, _ oid.ID, src io.ReadSeeker, _ neofscrypto.Signer, _ bool) (*neofscrypto.Signature, error) { +func (m *serviceClient) ReplicateObject(ctx context.Context, _ oid.ID, src io.ReadSeeker, _ neofscrypto.Signer, _ bool) (*neofscrypto.Signature, error) { objBin, err := io.ReadAll(src) if err != nil { return nil, err @@ -1085,7 +1085,7 @@ func (m *serviceClient) ReplicateObject(_ context.Context, _ oid.ID, src io.Read if err := obj.FromProtoMessage(&msg); err != nil { return nil, err } - return nil, (*Service)(m).ValidateAndStoreObjectLocally(obj) //nolint:contextcheck + return nil, (*Service)(m).ValidateAndStoreObjectLocally(ctx, obj) } func (m *serviceClient) ObjectDelete(context.Context, cid.ID, oid.ID, user.Signer, client.PrmObjectDelete) (oid.ID, error) { diff --git a/pkg/services/object/put/streamer.go b/pkg/services/object/put/streamer.go index 84e7123ce1..8372f6e570 100644 --- a/pkg/services/object/put/streamer.go +++ b/pkg/services/object/put/streamer.go @@ -77,6 +77,7 @@ func (p *Streamer) initTarget(prm *PutInitPrm) error { // prepare untrusted-Put object target p.target = &validatingTarget{ l: p.log, + ctx: p.ctx, nextTarget: p.newCommonTarget(prm), fmt: p.fmtValidator, quotaLimiter: p.quotaLimiter, @@ -146,6 +147,7 @@ func (p *Streamer) initTarget(prm *PutInitPrm) error { prm.sessionSigner = sessionSigner p.target = &validatingTarget{ l: p.log, + ctx: p.ctx, fmt: p.fmtValidator, unpreparedObject: true, quotaLimiter: p.quotaLimiter, diff --git a/pkg/services/object/put/validation.go b/pkg/services/object/put/validation.go index 9b7d2833a0..b70ca84fe8 100644 --- a/pkg/services/object/put/validation.go +++ b/pkg/services/object/put/validation.go @@ -2,6 +2,7 @@ package putsvc import ( "bytes" + "context" "crypto/sha256" "errors" "fmt" @@ -22,6 +23,8 @@ import ( type validatingTarget struct { l *zap.Logger + ctx context.Context + nextTarget internal.Target fmt *objectcore.FormatValidator @@ -92,7 +95,7 @@ func (t *validatingTarget) WriteHeader(obj *object.Object) error { t.checksum = cs.Value() } - if err := t.fmt.Validate(obj, t.unpreparedObject, false); err != nil { + if err := t.fmt.Validate(t.ctx, obj, t.unpreparedObject, false); err != nil { return fmt.Errorf("(%T) could not validate object format: %w", t, err) } diff --git a/pkg/services/object/server.go b/pkg/services/object/server.go index f1d14ec77e..a673c72cdc 100644 --- a/pkg/services/object/server.go +++ b/pkg/services/object/server.go @@ -143,11 +143,11 @@ type Storage interface { // VerifyAndStoreObjectLocally checks whether given object has correct format // and, if so, saves it in the Storage. StoreObject is called only when local // node complies with the container's storage policy. - VerifyAndStoreObjectLocally(object.Object) error + VerifyAndStoreObjectLocally(context.Context, object.Object) error // SearchObjects selects up to count container's objects from the given // container matching the specified filters. - SearchObjects(_ cid.ID, _ []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]sdkclient.SearchResultItem, []byte, error) + SearchObjects(_ context.Context, _ cid.ID, _ []objectcore.SearchFilter, attrs []string, cursor *objectcore.SearchCursor, count uint16) ([]sdkclient.SearchResultItem, []byte, error) } // ACLInfoExtractor is the interface that allows to fetch data required for ACL @@ -478,7 +478,7 @@ func (s *Server) Put(gStream protoobject.ObjectService_PutServer) error { err = basicACLErr(reqInfo) // needed for defer return s.sendStatusPutResponse(gStream, err, reqFirst) } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(gStream.Context(), req, reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) // needed for defer return s.sendStatusPutResponse(gStream, err, reqFirst) @@ -538,7 +538,7 @@ func (s *Server) Delete(ctx context.Context, req *protoobject.DeleteRequest) (*p err = basicACLErr(reqInfo) // needed for defer return s.makeStatusDeleteResponse(err, req), nil } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(ctx, req, reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) // needed for defer return s.makeStatusDeleteResponse(err, req), nil @@ -646,7 +646,7 @@ func (s *Server) HeadBuffered(ctx context.Context, req *protoobject.HeadRequest) err = basicACLErr(reqInfo) // needed for defer return s.makeStatusHeadResponse(err, needSignResp) } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(ctx, req, reqInfo) if err != nil { if !errors.Is(err, aclsvc.ErrNotMatched) { err = eACLErr(reqInfo, err) // needed for defer @@ -708,7 +708,7 @@ func (s *Server) HeadBuffered(ctx context.Context, req *protoobject.HeadRequest) } else { msg = &resp } - err = s.aclChecker.CheckEACL(msg, reqInfo) + err = s.aclChecker.CheckEACL(ctx, msg, reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) // defer return s.makeStatusHeadResponse(err, needSignResp) @@ -874,7 +874,7 @@ func (s *getStream) ValidateHeader(hdr *object.Object) error { }, } - err := s.srv.aclChecker.CheckEACL(resp, s.reqInfo) + err := s.srv.aclChecker.CheckEACL(s.base.Context(), resp, s.reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. return eACLErr(s.reqInfo, err) } @@ -950,7 +950,7 @@ func (s *Server) Get(req *protoobject.GetRequest, gStream protoobject.ObjectServ err = basicACLErr(reqInfo) // needed for defer return s.sendStatusGetResponse(gStream, err, needSignResp) } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(gStream.Context(), req, reqInfo) if err != nil { if !errors.Is(err, aclsvc.ErrNotMatched) { err = eACLErr(reqInfo, err) // needed for defer @@ -1014,7 +1014,7 @@ func (s *Server) Get(req *protoobject.GetRequest, gStream protoobject.ObjectServ } if recheckEACL { // previous check didn't match, but we have a header now. - err = s.aclChecker.CheckEACL(hdrBuf[hdrf.ValueFrom:hdrf.To], reqInfo) + err = s.aclChecker.CheckEACL(gStream.Context(), hdrBuf[hdrf.ValueFrom:hdrf.To], reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) // defer return s.sendStatusGetResponse(gStream, err, needSignResp) @@ -1309,7 +1309,7 @@ func (s *Server) GetRange(req *protoobject.GetRangeRequest, gStream protoobject. err = basicACLErr(reqInfo) // needed for defer return s.sendStatusRangeResponse(gStream, err, req) } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(gStream.Context(), req, reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) // needed for defer return s.sendStatusRangeResponse(gStream, err, req) @@ -1470,7 +1470,7 @@ func (s *Server) Search(_ *protoobject.SearchRequest, _ protoobject.ObjectServic } // Replicate serves neo.fs.v2.object.ObjectService/Replicate RPC. -func (s *Server) Replicate(_ context.Context, req *protoobject.ReplicateRequest) (*protoobject.ReplicateResponse, error) { +func (s *Server) Replicate(ctx context.Context, req *protoobject.ReplicateRequest) (*protoobject.ReplicateResponse, error) { if req.Object == nil { return &protoobject.ReplicateResponse{Status: &protostatus.Status{ Code: codeBadRequest, Message: "binary object field is missing/empty", @@ -1617,7 +1617,7 @@ func (s *Server) Replicate(_ context.Context, req *protoobject.ReplicateRequest) }}, nil } - err = s.storage.VerifyAndStoreObjectLocally(*obj) + err = s.storage.VerifyAndStoreObjectLocally(ctx, *obj) if err != nil { if errors.Is(err, apistatus.ErrBusy) { return &protoobject.ReplicateResponse{Status: apistatus.FromError(err)}, nil @@ -1682,7 +1682,7 @@ func (s *Server) SearchV2(ctx context.Context, req *protoobject.SearchV2Request) err = basicACLErr(reqInfo) // needed for defer return s.signSearchResponse(nil, err, req), nil } - err = s.aclChecker.CheckEACL(req, reqInfo) + err = s.aclChecker.CheckEACL(ctx, req, reqInfo) if err != nil && !errors.Is(err, aclsvc.ErrNotMatched) { // Not matched -> follow basic ACL. err = eACLErr(reqInfo, err) return s.signSearchResponse(nil, err, req), nil @@ -1826,7 +1826,7 @@ func (s *Server) ProcessSearch(ctx context.Context, req *protoobject.SearchV2Req ) switch { case ttl == 1: - if res, newCursor, err = s.storage.SearchObjects(cID, ofs, attrs, cursor, count); err != nil { + if res, newCursor, err = s.storage.SearchObjects(ctx, cID, ofs, attrs, cursor, count); err != nil { return nil, nil, err } case handleWithMetaService: @@ -1869,7 +1869,7 @@ func (s *Server) ProcessSearch(ctx context.Context, req *protoobject.SearchV2Req expectedRes++ if s.fsChain.IsOwnPublicKey(nodePub) { go func() { - set, crsr, err := s.storage.SearchObjects(cID, ofs, attrs, cursor, count) + set, crsr, err := s.storage.SearchObjects(ctx, cID, ofs, attrs, cursor, count) resCh <- nodeSearchResult{set, crsr != nil, err} }() return true diff --git a/pkg/services/object/server_test.go b/pkg/services/object/server_test.go index 9c66ae890d..0a648f78f5 100644 --- a/pkg/services/object/server_test.go +++ b/pkg/services/object/server_test.go @@ -106,10 +106,10 @@ func (c *noCallTestFSChain) InvokeContainedScript(*transaction.Transaction, *blo type noCallTestStorage struct{} -func (noCallTestStorage) SearchObjects(cid.ID, []objectcore.SearchFilter, []string, *objectcore.SearchCursor, uint16) ([]client.SearchResultItem, []byte, error) { +func (noCallTestStorage) SearchObjects(context.Context, cid.ID, []objectcore.SearchFilter, []string, *objectcore.SearchCursor, uint16) ([]client.SearchResultItem, []byte, error) { panic("must not be called") } -func (noCallTestStorage) VerifyAndStoreObjectLocally(object.Object) error { +func (noCallTestStorage) VerifyAndStoreObjectLocally(context.Context, object.Object) error { panic("must not be called") } func (noCallTestStorage) GetSessionPrivateKey(user.ID) (ecdsa.PrivateKey, error) { @@ -122,8 +122,10 @@ func (s noCallTestStorage) GetSessionV2PrivateKey([]sessionv2.Target) (ecdsa.Pri type noCallTestACLChecker struct{} -func (noCallTestACLChecker) CheckBasicACL(v2.RequestInfo) bool { panic("must not be called") } -func (noCallTestACLChecker) CheckEACL(any, v2.RequestInfo) error { panic("must not be called") } +func (noCallTestACLChecker) CheckBasicACL(v2.RequestInfo) bool { panic("must not be called") } +func (noCallTestACLChecker) CheckEACL(context.Context, any, v2.RequestInfo) error { + panic("must not be called") +} func (noCallTestACLChecker) StickyBitCheck(v2.RequestInfo, user.ID) bool { panic("must not be called") } type noCallTestReqInfoExtractor struct{} @@ -158,9 +160,9 @@ func (noCallClients) Get(context.Context, netmap.NodeInfo) (clientcore.MultiAddr type nopACLChecker struct{} -func (nopACLChecker) CheckBasicACL(v2.RequestInfo) bool { return true } -func (nopACLChecker) CheckEACL(any, v2.RequestInfo) error { return nil } -func (nopACLChecker) StickyBitCheck(v2.RequestInfo, user.ID) bool { return true } +func (nopACLChecker) CheckBasicACL(v2.RequestInfo) bool { return true } +func (nopACLChecker) CheckEACL(context.Context, any, v2.RequestInfo) error { return nil } +func (nopACLChecker) StickyBitCheck(v2.RequestInfo, user.ID) bool { return true } type nopReqInfoExtractor struct{} @@ -290,7 +292,7 @@ func newTestStorage(t testing.TB, obj *protoobject.Object) *testStorage { return &testStorage{t: t, obj: obj} } -func (x *testStorage) VerifyAndStoreObjectLocally(obj object.Object) error { +func (x *testStorage) VerifyAndStoreObjectLocally(_ context.Context, obj object.Object) error { require.Equal(x.t, x.obj, obj.ProtoMessage()) return x.storeErr } @@ -644,14 +646,14 @@ func (nopFSChain) LocalNodeUnderMaintenance() bool { return false } type nopStorage struct{} -func (nopStorage) VerifyAndStoreObjectLocally(object.Object) error { return nil } +func (nopStorage) VerifyAndStoreObjectLocally(context.Context, object.Object) error { return nil } func (nopStorage) GetSessionPrivateKey(user.ID) (ecdsa.PrivateKey, error) { return ecdsa.PrivateKey{}, apistatus.ErrSessionTokenNotFound } func (s nopStorage) GetSessionV2PrivateKey([]sessionv2.Target) (ecdsa.PrivateKey, error) { return ecdsa.PrivateKey{}, apistatus.ErrSessionTokenNotFound } -func (nopStorage) SearchObjects(cid.ID, []objectcore.SearchFilter, []string, *objectcore.SearchCursor, uint16) ([]client.SearchResultItem, []byte, error) { +func (nopStorage) SearchObjects(context.Context, cid.ID, []objectcore.SearchFilter, []string, *objectcore.SearchCursor, uint16) ([]client.SearchResultItem, []byte, error) { return nil, nil, nil } diff --git a/pkg/services/policer/check.go b/pkg/services/policer/check.go index 5aa07db674..0c525fb517 100644 --- a/pkg/services/policer/check.go +++ b/pkg/services/policer/check.go @@ -116,7 +116,7 @@ func (p *Policer) processObject(ctx context.Context, addrWithAttrs objectcore.Ad zap.Error(err), ) if container.IsErrNotFound(err) { - err = p.deleteLocalObject(addrWithAttrs.Address, isEC) + err = p.deleteLocalObject(ctx, addrWithAttrs.Address, isEC) if err != nil { p.log.Error("could not inhume object with missing container", zap.Stringer("cid", idCnr), @@ -135,7 +135,7 @@ func (p *Policer) processObject(ctx context.Context, addrWithAttrs objectcore.Ad } p.log.Info("object with EC attributes in container without EC rules detected, deleting", zap.Stringer("object", addr), zap.Int("ruleIdx", ecp.RuleIndex), zap.Int("partIdx", ecp.Index)) - if err := p.deleteLocalObject(addr, isEC); err != nil { + if err := p.deleteLocalObject(ctx, addr, isEC); err != nil { p.log.Error("failed to delete local object with excessive EC attributes", zap.Stringer("object", addr), zap.Error(err)) } @@ -157,7 +157,7 @@ func (p *Policer) processObject(ctx context.Context, addrWithAttrs objectcore.Ad } else if len(repRules) == 0 { p.log.Info("object with lacking EC attributes detected, deleting", zap.Stringer("object", addr)) - if err := p.deleteLocalObject(addr, false); err != nil { + if err := p.deleteLocalObject(ctx, addr, false); err != nil { p.log.Error("failed to delete local object with lacking EC attributes", zap.Stringer("object", addr), zap.Error(err)) } @@ -225,11 +225,11 @@ func (p *Policer) processObject(ctx context.Context, addrWithAttrs objectcore.Ad ) } - p.dropRedundantLocalObject(addr, false) + p.dropRedundantLocalObject(ctx, addr, false) return } - p.dropRedundantLocalCopies(addrWithAttrs) + p.dropRedundantLocalCopies(ctx, addrWithAttrs) } type processPlacementContext struct { @@ -374,23 +374,23 @@ func (p *Policer) processNodes(ctx context.Context, plc *processPlacementContext } } -func (p *Policer) dropRedundantLocalObject(addr oid.Address, isEC bool) { - err := p.deleteLocalObject(addr, isEC) +func (p *Policer) dropRedundantLocalObject(ctx context.Context, addr oid.Address, isEC bool) { + err := p.deleteLocalObject(ctx, addr, isEC) if err != nil { p.log.Warn("could not inhume mark redundant copy as garbage", zap.Error(err)) } } -func (p *Policer) deleteLocalObject(addr oid.Address, isEC bool) error { - err := p.localStorage.Delete(addr) +func (p *Policer) deleteLocalObject(ctx context.Context, addr oid.Address, isEC bool) error { + err := p.localStorage.Delete(ctx, addr) if err == nil { p.metrics.IncPolicerObjectDeleted(isEC) } return err } -func (p *Policer) dropRedundantLocalCopies(obj objectcore.AddressWithAttributes) { +func (p *Policer) dropRedundantLocalCopies(ctx context.Context, obj objectcore.AddressWithAttributes) { if len(obj.ShardIDs) < 2 { return } @@ -401,7 +401,7 @@ func (p *Policer) dropRedundantLocalCopies(obj objectcore.AddressWithAttributes) default: } - err := p.localStorage.DeleteRedundantCopies(obj.Address, obj.ShardIDs) + err := p.localStorage.DeleteRedundantCopies(ctx, obj.Address, obj.ShardIDs) if err != nil { p.log.Warn("could not mark redundant local shard copies as garbage", zap.Stringer("object", obj.Address), diff --git a/pkg/services/policer/ec.go b/pkg/services/policer/ec.go index a8efd9d5fd..5164fdd6e2 100644 --- a/pkg/services/policer/ec.go +++ b/pkg/services/policer/ec.go @@ -24,7 +24,7 @@ func (p *Policer) processECPart(ctx context.Context, addr oid.Address, parent oi if pi.RuleIndex >= len(ecRules) { p.log.Warn("local object with invalid EC rule index detected, deleting", zap.Stringer("object", addr), zap.Int("ruleIdx", pi.RuleIndex), zap.Int("totalRules", len(ecRules))) - if err := p.deleteLocalObject(addr, true); err != nil { + if err := p.deleteLocalObject(ctx, addr, true); err != nil { p.log.Error("failed to delete local object with invalid EC rule index", zap.Stringer("object", addr), zap.Error(err)) } @@ -35,7 +35,7 @@ func (p *Policer) processECPart(ctx context.Context, addr oid.Address, parent oi if pi.Index >= int(rule.DataPartNum+rule.ParityPartNum) { p.log.Warn("local object with invalid EC part index detected, deleting", zap.Stringer("object", addr), zap.Stringer("rule", rule), zap.Int("partIdx", pi.Index)) - if err := p.deleteLocalObject(addr, true); err != nil { + if err := p.deleteLocalObject(ctx, addr, true); err != nil { p.log.Error("failed to delete local object with invalid EC part index", zap.Stringer("object", addr), zap.Error(err)) } @@ -75,7 +75,7 @@ func (p *Policer) processECPartByRule(ctx context.Context, rule iec.Rule, addr o zap.Stringer("cid", addr.Container()), zap.Stringer("partOID", addr.Object()), zap.Stringer("rule", rule), zap.Int("partIdx", partIdx), zap.Strings("node", slices.Collect(nodes[i].NetworkEndpoints()))) - p.dropRedundantLocalObject(addr, true) + p.dropRedundantLocalObject(ctx, addr, true) return } @@ -121,7 +121,7 @@ func (p *Policer) processECPartByRule(ctx context.Context, rule iec.Rule, addr o p.log.Info("EC part successfully moved to more optimal node, drop", zap.Stringer("cid", addr.Container()), zap.Stringer("partOID", addr.Object()), zap.Stringer("rule", rule), zap.Int("partIdx", partIdx), zap.Strings("newHolder", repRes.netAddresses)) - p.dropRedundantLocalObject(addr, true) + p.dropRedundantLocalObject(ctx, addr, true) return } @@ -190,7 +190,7 @@ headNextPart: var hdr object.Object local := p.network.IsLocalNodePublicKey(sortedNodes[nodeIdx].PublicKey()) if local { - hdr, err = p.localStorage.HeadECPart(cnr, parent, iec.PartInfo{RuleIndex: ruleIdx, Index: partIdx}) + hdr, err = p.localStorage.HeadECPart(ctx, cnr, parent, iec.PartInfo{RuleIndex: ruleIdx, Index: partIdx}) } else { if partIdxAttr == "" { partIdxAttr = strconv.Itoa(partIdx) @@ -268,7 +268,7 @@ headNextPart: if parentHdr.GetID().IsZero() { // can only happen for 1/1 rule: local part is never HEADed in for-loop above and remote one is unreachable - hdr, err := p.localStorage.Head(parentAddr, false) + hdr, err := p.localStorage.Head(ctx, parentAddr, false) if err != nil { p.log.Info("failed to get EC parent header locally", zap.Stringer("container", cnr), zap.Stringer("parent", parent), zap.Stringer("rule", rule), @@ -299,7 +299,7 @@ getNextPart: } if partIdx == localPartIdx { - b, err := p.localStorage.GetRange(oid.NewAddress(cnr, partID), 0, 0) + b, err := p.localStorage.GetRange(ctx, oid.NewAddress(cnr, partID), 0, 0) if err == nil { parts[partIdx] = b continue @@ -318,7 +318,7 @@ getNextPart: continue } - b, err := p.localStorage.GetRange(oid.NewAddress(cnr, partID), off, ln) + b, err := p.localStorage.GetRange(ctx, oid.NewAddress(cnr, partID), off, ln) if err != nil { p.log.Info("failed to RANGE EC part from local storage", zap.Stringer("container", cnr), zap.Stringer("parent", parent), zap.Stringer("rule", rule), diff --git a/pkg/services/policer/policer.go b/pkg/services/policer/policer.go index 8dc1913b02..9953f7f03b 100644 --- a/pkg/services/policer/policer.go +++ b/pkg/services/policer/policer.go @@ -27,13 +27,13 @@ type replicatorIface interface { // interface of [engine.StorageEngine] used by [Policer] for overriding in tests. type localStorage interface { - ListWithCursor(uint32, *engine.Cursor, ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) - Delete(oid.Address) error - DeleteRedundantCopies(oid.Address, []string) error - Put(*object.Object, []byte) error - Head(oid.Address, bool) (*object.Object, error) - HeadECPart(cid.ID, oid.ID, iec.PartInfo) (object.Object, error) - GetRange(oid.Address, uint64, uint64) ([]byte, error) + ListWithCursor(context.Context, uint32, *engine.Cursor, ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) + Delete(context.Context, oid.Address) error + DeleteRedundantCopies(context.Context, oid.Address, []string) error + Put(context.Context, *object.Object, []byte) error + Head(context.Context, oid.Address, bool) (*object.Object, error) + HeadECPart(context.Context, cid.ID, oid.ID, iec.PartInfo) (object.Object, error) + GetRange(context.Context, oid.Address, uint64, uint64) ([]byte, error) } // interface of [headsvc.RemoteHeader] used by [Policer] for overriding in tests. diff --git a/pkg/services/policer/policer_test.go b/pkg/services/policer/policer_test.go index ce4956bc23..555c6091aa 100644 --- a/pkg/services/policer/policer_test.go +++ b/pkg/services/policer/policer_test.go @@ -49,34 +49,34 @@ func (s *storageListerWithDelay) setListResulsts(oo []objectcore.AddressWithAttr s.m.Unlock() } -func (s *storageListerWithDelay) ListWithCursor(u uint32, cursor *engine.Cursor, s2 ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) { +func (s *storageListerWithDelay) ListWithCursor(_ context.Context, u uint32, cursor *engine.Cursor, s2 ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) { <-s.ch s.m.RLock() defer s.m.RUnlock() return s.objs, cursor, s.err } -func (s *storageListerWithDelay) Delete(address oid.Address) error { +func (s *storageListerWithDelay) Delete(_ context.Context, address oid.Address) error { panic("do not call me") } -func (s *storageListerWithDelay) DeleteRedundantCopies(address oid.Address, _ []string) error { +func (s *storageListerWithDelay) DeleteRedundantCopies(_ context.Context, address oid.Address, _ []string) error { panic("do not call me") } -func (s *storageListerWithDelay) Put(o *object.Object, i []byte) error { +func (s *storageListerWithDelay) Put(_ context.Context, o *object.Object, i []byte) error { panic("do not call me") } -func (s *storageListerWithDelay) Head(address oid.Address, b bool) (*object.Object, error) { +func (s *storageListerWithDelay) Head(_ context.Context, address oid.Address, b bool) (*object.Object, error) { panic("do not call me") } -func (s *storageListerWithDelay) HeadECPart(id cid.ID, id2 oid.ID, info iec.PartInfo) (object.Object, error) { +func (s *storageListerWithDelay) HeadECPart(_ context.Context, id cid.ID, id2 oid.ID, info iec.PartInfo) (object.Object, error) { panic("do not call me") } -func (s *storageListerWithDelay) GetRange(address oid.Address, u uint64, u2 uint64) ([]byte, error) { +func (s *storageListerWithDelay) GetRange(_ context.Context, address oid.Address, u uint64, u2 uint64) ([]byte, error) { panic("do not call me") } @@ -216,8 +216,8 @@ func TestConsistencyAndPlacement(t *testing.T) { repAddr := oid.NewAddress(cidtest.ID(), oidtest.ID()) ecAddr := oid.NewAddress(cidtest.ID(), oidtest.ID()) - p.dropRedundantLocalObject(repAddr, false) - p.dropRedundantLocalObject(ecAddr, true) + p.dropRedundantLocalObject(context.Background(), repAddr, false) + p.dropRedundantLocalObject(context.Background(), ecAddr, true) require.EqualValues(t, 1, mockM.deletedRep.Load()) require.EqualValues(t, 1, mockM.deletedEC.Load()) @@ -1499,7 +1499,7 @@ func (x *mockNetwork) PublicKey() []byte { return x.pubKey } -func (x *testLocalNode) ListWithCursor(_ uint32, c *engine.Cursor, _ ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) { +func (x *testLocalNode) ListWithCursor(_ context.Context, _ uint32, c *engine.Cursor, _ ...string) ([]objectcore.AddressWithAttributes, *engine.Cursor, error) { if len(x.objList) == 0 { return nil, nil, engine.ErrEndOfListing } @@ -1549,30 +1549,30 @@ func (x *testLocalNode) deletedShardCopies(addr oid.Address) []string { return res } -func (x *testLocalNode) Delete(addr oid.Address) error { +func (x *testLocalNode) Delete(_ context.Context, addr oid.Address) error { x.delMtx.Lock() x.del[addr] = struct{}{} x.delMtx.Unlock() return nil } -func (x *testLocalNode) Put(*object.Object, []byte) error { +func (x *testLocalNode) Put(_ context.Context, _ *object.Object, _ []byte) error { return nil } -func (x *testLocalNode) Head(oid.Address, bool) (*object.Object, error) { +func (x *testLocalNode) Head(_ context.Context, _ oid.Address, _ bool) (*object.Object, error) { return &object.Object{}, nil } -func (x *testLocalNode) HeadECPart(cid.ID, oid.ID, iec.PartInfo) (object.Object, error) { +func (x *testLocalNode) HeadECPart(_ context.Context, _ cid.ID, _ oid.ID, _ iec.PartInfo) (object.Object, error) { return object.Object{}, nil } -func (x *testLocalNode) GetRange(oid.Address, uint64, uint64) ([]byte, error) { +func (x *testLocalNode) GetRange(_ context.Context, _ oid.Address, _ uint64, _ uint64) ([]byte, error) { panic("unimplemented") } -func (x *testLocalNode) DeleteRedundantCopies(addr oid.Address, shardIDs []string) error { +func (x *testLocalNode) DeleteRedundantCopies(_ context.Context, addr oid.Address, shardIDs []string) error { if x.deleteRedundantCopies != nil { return x.deleteRedundantCopies(addr, shardIDs) } diff --git a/pkg/services/policer/process.go b/pkg/services/policer/process.go index 83056bd619..2298001ec0 100644 --- a/pkg/services/policer/process.go +++ b/pkg/services/policer/process.go @@ -137,7 +137,7 @@ func (p *Policer) shardPolicyWorker(ctx context.Context) { batchSize *= boostMultiplier } - addrs, cursor, err = p.localStorage.ListWithCursor(batchSize, cursor, iec.AttributeRuleIdx, iec.AttributePartIdx, object.FilterParentID) + addrs, cursor, err = p.localStorage.ListWithCursor(ctx, batchSize, cursor, iec.AttributeRuleIdx, iec.AttributePartIdx, object.FilterParentID) if err != nil { if errors.Is(err, engine.ErrEndOfListing) { if wrapped { diff --git a/pkg/services/replicator/process.go b/pkg/services/replicator/process.go index 338c8b0f3c..1dd0e55d6c 100644 --- a/pkg/services/replicator/process.go +++ b/pkg/services/replicator/process.go @@ -44,7 +44,7 @@ func (p *Replicator) HandleTask(ctx context.Context, task Task, res TaskResult) objBin = task.obj.Marshal() stream = bytes.NewReader(objBin) } else { - objBin, err = p.localStorage.GetBytes(task.addr) + objBin, err = p.localStorage.GetBytes(ctx, task.addr) if err != nil { p.log.Error("could not get object from local storage", zap.Stringer("object", task.addr), @@ -75,7 +75,7 @@ func (p *Replicator) HandleTask(ctx context.Context, task Task, res TaskResult) log.Debug("cannot put object to local storage: object not provided in task") continue } - if err = p.localStorage.Put(task.obj, objBin); err != nil { + if err = p.localStorage.Put(ctx, task.obj, objBin); err != nil { log.Error("could not put object to local storage", zap.Error(err)) continue }