Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

object: Separate API for node-to-node replication #280

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions object/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ option csharp_namespace = "Neo.FileStorage.API.Object";
import "object/types.proto";
import "refs/types.proto";
import "session/types.proto";
import "status/types.proto";

// `ObjectService` provides API for manipulating objects. Object operations do
// not affect the sidechain and are only served by nodes in p2p style.
Expand Down Expand Up @@ -218,6 +219,23 @@ service ObjectService {
// - **TOKEN_EXPIRED** (4097, SECTION_SESSION): \
// provided session token has expired.
rpc GetRangeHash(GetRangeHashRequest) returns (GetRangeHashResponse);

// Save replica of the object on the NeoFS storage node. Both client and
// server must authenticate NeoFS storage nodes matching storage policy of
// the container referenced by the replicated object. Thus, this operation is
// purely system: regular users should not pay attention to it but use Put.
//
// Statuses:
// - **OK** (0, SECTION_SUCCESS): \
// the object has been successfully replicated;
// - **INTERNAL_SERVER_ERROR** (1024, SECTION_FAILURE_COMMON): \
// internal server error described in the text message;
// - **ACCESS_DENIED** (2048, SECTION_OBJECT): \
// the client does not authenticate any NeoFS storage node matching storage
// policy of the container referenced by the replicated object
// - **CONTAINER_NOT_FOUND** (3072, SECTION_CONTAINER): \
// the container to which the replicated object is associated was not found.
rpc Replicate(ReplicateRequest) returns (ReplicateResponse);
}

// GET object request
Expand Down Expand Up @@ -688,3 +706,19 @@ message GetRangeHashResponse {
// transmission.
neo.fs.v2.session.ResponseVerificationHeader verify_header = 3;
}

// Replicate RPC request
message ReplicateRequest {
// Object to be replicated.
neo.fs.v2.object.Object object = 1;

// Signature of all other request fields serialized in Protocol Buffers v3
// format in ascending order of fields.
neo.fs.v2.refs.Signature signature = 2;
}

// Replicate RPC response
message ReplicateResponse {
// Operation execution status with one of the enumerated codes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would say it is an incorrect comment now. i see Status, no enumeration

neo.fs.v2.status.Status status = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the simplicity of it, but this breaks https://github.com/nspcc-dev/neofs-sdk-go/blob/master/client/response.go and associated code around it. Does it affect integration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, integration is ok cuz this is purely new functionality. If protocol doesnt require signature (if we keep the current status-only response), then applications must not too

the only tricky thing i see is #201 (comment), but there are app-side workarounds

the main thing for us is to think carefully about whether we need a signature from the protocol pov. And ofc, when in doubt, it is better to add it and then make it optional, because further additions must be optional for the backward compat sake. But, at the same time, the benefits are questionable while the resource costs are real

im leaning more towards the option without a signature as more efficient, but I'm not completely sure yet. Share ur thoughts pls @roman-khimov @carpawell

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signatures make some sense for insecure connections or for rerouted messages, but for TLS-enabled 1:1 calls they're irrelevant. And then there is also some benefit in having insecure unsigned option for fast communication over known good channels. So if this inconsistency is not an obstacle, we better go without signatures.

Now for the other data like epochs, is it important for us to get it with every reply? I doubt that, but maybe I'm missing something. This data costs nothing to transmit/receive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thoughts about transport security. Can we spread this to requests also? In proposed changes, replication requests are signed while responses are not

to get it with every reply

absolutely not. For me, this is redundancy useful for a narrow set of tasks (mostly system ones), which should not be unconditionally transferred. I see the behavior: if client set flag in the request, epoch/smth will be returned, not by default. Although the amount of data like epoch is insignificant, it is still pointless to transfer it when not needed by the client

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think a signature absence is acceptable for a system-only RPC response

}
47 changes: 47 additions & 0 deletions proto-docs/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
- [PutResponse](#neo.fs.v2.object.PutResponse)
- [PutResponse.Body](#neo.fs.v2.object.PutResponse.Body)
- [Range](#neo.fs.v2.object.Range)
- [ReplicateRequest](#neo.fs.v2.object.ReplicateRequest)
- [ReplicateResponse](#neo.fs.v2.object.ReplicateResponse)
- [SearchRequest](#neo.fs.v2.object.SearchRequest)
- [SearchRequest.Body](#neo.fs.v2.object.SearchRequest.Body)
- [SearchRequest.Body.Filter](#neo.fs.v2.object.SearchRequest.Body.Filter)
Expand Down Expand Up @@ -80,6 +82,7 @@ rpc Head(HeadRequest) returns (HeadResponse);
rpc Search(SearchRequest) returns (stream SearchResponse);
rpc GetRange(GetRangeRequest) returns (stream GetRangeResponse);
rpc GetRangeHash(GetRangeHashRequest) returns (GetRangeHashResponse);
rpc Replicate(ReplicateRequest) returns (ReplicateResponse);

```

Expand Down Expand Up @@ -318,6 +321,27 @@ Statuses:
| Name | Input | Output |
| ---- | ----- | ------ |
| GetRangeHash | [GetRangeHashRequest](#neo.fs.v2.object.GetRangeHashRequest) | [GetRangeHashResponse](#neo.fs.v2.object.GetRangeHashResponse) |
#### Method Replicate

Save replica of the object on the NeoFS storage node. Both client and
server must authenticate NeoFS storage nodes matching storage policy of
the container referenced by the replicated object. Thus, this operation is
purely system: regular users should not pay attention to it but use Put.

Statuses:
- **OK** (0, SECTION_SUCCESS): \
the object has been successfully replicated;
- **INTERNAL_SERVER_ERROR** (1024, SECTION_FAILURE_COMMON): \
internal server error described in the text message;
- **ACCESS_DENIED** (2048, SECTION_OBJECT): \
the client does not authenticate any NeoFS storage node matching storage
policy of the container referenced by the replicated object
- **CONTAINER_NOT_FOUND** (3072, SECTION_CONTAINER): \
the container to which the replicated object is associated was not found.

| Name | Input | Output |
| ---- | ----- | ------ |
| Replicate | [ReplicateRequest](#neo.fs.v2.object.ReplicateRequest) | [ReplicateResponse](#neo.fs.v2.object.ReplicateResponse) |
<!-- end services -->


Expand Down Expand Up @@ -687,6 +711,29 @@ Object payload range. Ranges of zero length SHOULD be considered as invalid.
| length | [uint64](#uint64) | | Length in bytes of the object payload range |


<a name="neo.fs.v2.object.ReplicateRequest"></a>

### Message ReplicateRequest
Replicate RPC request


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| object | [Object](#neo.fs.v2.object.Object) | | Object to be replicated. |
| signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of all other request fields serialized in Protocol Buffers v3 format in ascending order of fields. |


<a name="neo.fs.v2.object.ReplicateResponse"></a>

### Message ReplicateResponse
Replicate RPC response


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| status | [neo.fs.v2.status.Status](#neo.fs.v2.status.Status) | | Operation execution status with one of the enumerated codes. |


<a name="neo.fs.v2.object.SearchRequest"></a>

### Message SearchRequest
Expand Down
Loading